revert-large-file-support-20030328
[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/unified_afs.h>
113 #include <afs/audit.h>
114 #include <afs/afsutil.h>
115
116 #ifdef AFS_PTHREAD_ENV
117 pthread_mutex_t fileproc_glock_mutex;
118 #endif /* AFS_PTHREAD_ENV */
119
120
121 /* Useful local defines used by this module */
122
123 #define DONTCHECK       0
124 #define MustNOTBeDIR    1
125 #define MustBeDIR       2
126
127 #define TVS_SDATA       1
128 #define TVS_SSTATUS     2
129 #define TVS_CFILE       4
130 #define TVS_SLINK       8
131 #define TVS_MKDIR       0x10
132
133 #define CHK_FETCH       0x10
134 #define CHK_FETCHDATA   0x10
135 #define CHK_FETCHACL    0x11
136 #define CHK_FETCHSTATUS 0x12
137 #define CHK_STOREDATA   0x00
138 #define CHK_STOREACL    0x01
139 #define CHK_STORESTATUS 0x02
140
141 #define OWNERREAD       0400
142 #define OWNERWRITE      0200
143 #define OWNEREXEC       0100
144 #ifdef USE_GROUP_PERMS
145 #define GROUPREAD       0040
146 #define GROUPWRITE      0020
147 #define GROUPREXEC      0010
148 #endif
149
150 /* The following errors were not defined in NT. They are given unique
151  * names here to avoid any potential collision.
152  */
153 #define FSERR_ELOOP              90
154 #define FSERR_EOPNOTSUPP        122
155 #define FSERR_ECONNREFUSED      130
156
157 #define NOTACTIVECALL   0
158 #define ACTIVECALL      1
159
160 #define CREATE_SGUID_ADMIN_ONLY 1
161
162 extern struct afsconf_dir *confDir;
163 extern afs_int32 dataVersionHigh;
164
165 extern  int         SystemId;
166 static struct AFSCallStatistics AFSCallStats;
167 #if FS_STATS_DETAILED
168 struct fs_stats_FullPerfStats afs_FullPerfStats;
169 extern int AnonymousID;
170 #endif /* FS_STATS_DETAILED */
171 #if OPENAFS_VOL_STATS
172 static const char nullString[] = "";
173 #endif /* OPENAFS_VOL_STATS */
174
175 struct afs_FSStats {
176     afs_int32 NothingYet;
177 };
178
179 struct afs_FSStats afs_fsstats;
180
181 void    ResetDebug(), SetDebug(), Terminate();
182
183 int     LogLevel = 0;
184 int     supported = 1;
185 int     Console = 0;
186 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
187 afs_int32 PctSpare;
188 extern afs_int32 implicitAdminRights;
189 extern afs_int32 readonlyServer;
190
191 /*
192  * Externals used by the xstat code.
193  */
194 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
195 extern int CEs, CEBlocks;
196
197 extern int HTs, HTBlocks;
198
199 afs_int32
200 FetchData_RXStyle(Volume *volptr, 
201                   Vnode *targetptr, 
202                   register struct rx_call *Call,
203                   afs_int32 Pos,
204                   afs_int32 Len,
205                   afs_int32 Int64Mode,
206 #if FS_STATS_DETAILED
207                   afs_int32 *a_bytesToFetchP,
208                   afs_int32 *a_bytesFetchedP
209 #endif /* FS_STATS_DETAILED */
210                   );
211
212 afs_int32
213 StoreData_RXStyle(Volume *volptr,
214                   Vnode *targetptr,
215                   struct AFSFid *Fid,
216                   struct client *client,
217                   register struct rx_call *Call,
218                   afs_uint32 Pos,
219                   afs_uint32 Length,
220                   afs_uint32 FileLength,
221                   int sync,
222 #if FS_STATS_DETAILED
223                   afs_int32 *a_bytesToStoreP,
224                   afs_int32 *a_bytesStoredP
225 #endif /* FS_STATS_DETAILED */
226                   );
227
228 #ifdef AFS_SGI_XFS_IOPS_ENV
229 #include <afs/xfsattrs.h>
230 static int GetLinkCount(Volume *avp, struct stat *astat)
231 {
232     if (!strcmp("xfs", astat->st_fstype)) {
233         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
234     }
235     else
236         return astat->st_nlink;
237 }
238 #else
239 #define GetLinkCount(V, S) (S)->st_nlink
240 #endif
241
242 afs_int32 SpareComp(Volume *avolp)
243 {
244     register afs_int32 temp;
245
246     FS_LOCK
247     if (PctSpare) {
248         temp = V_maxquota(avolp);
249         if (temp == 0) {
250             /* no matter; doesn't check in this case */
251             FS_UNLOCK
252             return 0;
253         }
254         temp = (temp * PctSpare) / 100;
255         FS_UNLOCK
256         return temp;
257     }
258     else {
259         FS_UNLOCK
260         return BlocksSpare;
261     }
262
263 } /*SpareComp*/
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) || (thost->hostFlags & HFE_LATER)){
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), 
353                         ntohs(thost->port)));
354             code = -1;
355         } else {
356             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
357                         afs_inet_ntoa_r(thost->host, hoststr), 
358                         ntohs(thost->port)));
359             if (BreakDelayedCallBacks_r(thost)) {
360                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
361                         afs_inet_ntoa_r(thost->host, hoststr)));
362                 code = -1;
363             }
364         }
365       }
366     } else {
367        code =  0;
368     }
369
370     h_ReleaseClient_r(tclient);
371     h_Unlock_r(thost);
372     H_UNLOCK
373     return code;      
374
375 } /*CallPreamble*/
376
377
378 static afs_int32 CallPostamble(register struct rx_connection *aconn,
379                                afs_int32 ret)
380 {
381     struct host *thost;
382     struct client *tclient;
383     int translate = 0;
384
385     H_LOCK
386     tclient = h_FindClient_r(aconn);
387     thost = tclient->host;
388     if (thost->hostFlags & HERRORTRANS) translate = 1;
389     h_ReleaseClient_r(tclient);
390     h_Release_r(thost);
391     H_UNLOCK
392
393     return (translate ? sys_error_to_et(ret) : ret);
394 } /*CallPostamble*/
395
396 /*
397  * Returns the volume and vnode pointers associated with file Fid; the lock
398  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
399  * are incremented and they must be eventualy released.
400  */
401 static afs_int32
402 CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock)
403 {
404     int fileCode = 0;
405     int errorCode = -1;
406     static struct timeval restartedat = {0,0};
407
408     if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
409         return(EINVAL);
410     if ((*volptr) == 0) {
411       extern int VInit;
412
413       while(1) {
414         errorCode = 0;
415         *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
416         if (!errorCode) {
417           assert (*volptr);
418           break;
419         }
420         if ((errorCode == VOFFLINE) && (VInit < 2)) {
421             /* The volume we want may not be attached yet because
422              * the volume initialization is not yet complete.
423              * We can do several things: 
424              *     1.  return -1, which will cause users to see
425              *         "connection timed out".  This is more or
426              *         less the same as always, except that the servers
427              *         may appear to bounce up and down while they
428              *         are actually restarting.
429              *     2.  return VBUSY which will cause clients to 
430              *         sleep and retry for 6.5 - 15 minutes, depending
431              *         on what version of the CM they are running.  If
432              *         the file server takes longer than that interval 
433              *         to attach the desired volume, then the application
434              *         will see an ENODEV or EIO.  This approach has 
435              *         the advantage that volumes which have been attached
436              *         are immediately available, it keeps the server's
437              *         immediate backlog low, and the call is interruptible
438              *         by the user.  Users see "waiting for busy volume."
439              *     3.  sleep here and retry.  Some people like this approach
440              *         because there is no danger of seeing errors.  However, 
441              *         this approach only works with a bounded number of 
442              *         clients, since the pending queues will grow without
443              *         stopping.  It might be better to find a way to take
444              *         this call and stick it back on a queue in order to
445              *         recycle this thread for a different request.    
446              *     4.  Return a new error code, which new cache managers will
447              *         know enough to interpret as "sleep and retry", without
448              *         the upper bound of 6-15 minutes that is imposed by the
449              *         VBUSY handling.  Users will see "waiting for
450              *         busy volume," so they know that something is
451              *         happening.  Old cache managers must be able to do  
452              *         something reasonable with this, for instance, mark the
453              *         server down.  Fortunately, any error code < 0
454              *         will elicit that behavior. See #1.
455              *     5.  Some combination of the above.  I like doing #2 for 10
456              *         minutes, followed by #4.  3.1b and 3.2 cache managers
457              *         will be fine as long as the restart period is
458              *         not longer than 6.5 minutes, otherwise they may
459              *         return ENODEV to users.  3.3 cache managers will be
460              *         fine for 10 minutes, then will return
461              *         ETIMEDOUT.  3.4 cache managers will just wait
462              *         until the call works or fails definitively.
463              *  NB. The problem with 2,3,4,5 is that old clients won't
464              *  fail over to an alternate read-only replica while this
465              *  server is restarting.  3.4 clients will fail over right away.
466              */
467           if (restartedat.tv_sec == 0) {
468             /* I'm not really worried about when we restarted, I'm   */
469             /* just worried about when the first VBUSY was returned. */
470             TM_GetTimeOfDay(&restartedat, 0);
471             return(busyonrst?VBUSY:VRESTARTING);
472           }
473           else {
474             struct timeval now;
475             TM_GetTimeOfDay(&now, 0);
476             if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
477               return(busyonrst?VBUSY:VRESTARTING);
478             }
479             else {
480               return (VRESTARTING);
481             }
482           }
483         }
484           /* allow read operations on busy volume */
485         else if(errorCode==VBUSY && lock==READ_LOCK) {
486           errorCode=0;
487           break;
488         }
489         else if (errorCode)
490           return(errorCode);
491       }
492     }
493     assert (*volptr);
494
495     /* get the vnode  */
496     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
497     if (errorCode)
498         return(errorCode);
499     if ((*vptr)->disk.uniquifier != fid->Unique) {
500         VPutVnode(&fileCode, *vptr);
501         assert(fileCode == 0);
502         *vptr = 0;
503         return(VNOVNODE);   /* return the right error code, at least */
504     }
505     return(0);
506 } /*CheckVnode*/
507
508 /*
509  * This routine returns the ACL associated with the targetptr. If the
510  * targetptr isn't a directory, we access its parent dir and get the ACL
511  * thru the parent; in such case the parent's vnode is returned in
512  * READ_LOCK mode.
513  */
514 static afs_int32
515 SetAccessList(Vnode **targetptr,
516               Volume **volume,
517               struct acl_accessList **ACL,
518               int * ACLSize,
519               Vnode **parent,
520               AFSFid *Fid,
521               int Lock)
522 {
523     if ((*targetptr)->disk.type == vDirectory) {
524         *parent = 0;
525         *ACL = VVnodeACL(*targetptr);
526         *ACLSize = VAclSize(*targetptr);
527         return(0);
528     }
529     else {
530         assert(Fid != 0);
531         while(1) {
532             VnodeId parentvnode;
533             int errorCode = 0;
534             
535             parentvnode = (*targetptr)->disk.parent;
536             VPutVnode(&errorCode,*targetptr);
537             *targetptr = 0;
538             if (errorCode) return(errorCode);
539             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
540             if (errorCode) return(errorCode);
541             *ACL = VVnodeACL(*parent);
542             *ACLSize = VAclSize(*parent);
543             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
544                 return(errorCode);
545             if ((*targetptr)->disk.parent != parentvnode) {
546                 VPutVnode(&errorCode, *parent);
547                 *parent = 0;
548                 if (errorCode) return(errorCode);
549             } else
550                 return(0);
551         }
552     }
553
554 } /*SetAccessList*/
555
556 /*
557  * Compare the directory's ACL with the user's access rights in the client
558  * connection and return the user's and everybody else's access permissions
559  * in rights and anyrights, respectively
560  */
561 static afs_int32
562 GetRights (struct client *client,
563            struct acl_accessList *ACL,
564            afs_int32 *rights,
565            afs_int32 *anyrights)
566 {
567     extern prlist SystemAnyUserCPS;
568     afs_int32 hrights = 0;
569     int code;
570
571     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
572
573         ViceLog(0,("CheckRights failed\n"));
574         *anyrights = 0;
575     }
576     *rights = 0;
577     acl_CheckRights(ACL, &client->CPS, rights);
578
579         /* wait if somebody else is already doing the getCPS call */
580     H_LOCK
581     while ( client->host->hostFlags & HCPS_INPROGRESS )
582     {
583         client->host->hostFlags |= HCPS_WAITING;  /* I am waiting */
584 #ifdef AFS_PTHREAD_ENV
585         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
586 #else /* AFS_PTHREAD_ENV */
587         if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
588                 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
589 #endif /* AFS_PTHREAD_ENV */
590     }
591
592     if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
593         ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
594     } else
595         acl_CheckRights(ACL, &client->host->hcps, &hrights);
596     H_UNLOCK
597     /* Allow system:admin the rights given with the -implicit option */
598     if (acl_IsAMember(SystemId, &client->CPS))
599         *rights |= implicitAdminRights;
600     *rights |= hrights;
601     *anyrights |= hrights;
602
603     return(0);
604
605 } /*GetRights*/
606
607 /*
608  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
609  * a System:Administrator)
610  */
611 static afs_int32
612 VanillaUser(struct client *client)
613 {
614     if (acl_IsAMember(SystemId, &client->CPS))
615         return(0);  /* not a system administrator, then you're "vanilla" */
616     return(1);
617
618 } /*VanillaUser*/
619
620
621 /*
622  * This unusual afs_int32-parameter routine encapsulates all volume package related
623  * operations together in a single function; it's called by almost all AFS
624  * interface calls.
625  */
626 static afs_int32
627 GetVolumePackage(struct rx_connection *tcon,
628                  AFSFid *Fid,
629                  Volume **volptr,
630                  Vnode **targetptr,
631                  int chkforDir,
632                  Vnode **parent,
633                  struct client **client,
634                  int locktype,
635                  afs_int32 *rights, 
636                  afs_int32 *anyrights)
637 {
638     struct acl_accessList * aCL;    /* Internal access List */
639     int aCLSize;            /* size of the access list */
640     int errorCode = 0;      /* return code to caller */
641
642     if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
643         return(errorCode);
644     if (chkforDir) {
645         if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
646             return(EISDIR);
647         else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
648             return(ENOTDIR);
649     }
650     if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
651         return(errorCode);
652     if (chkforDir == MustBeDIR) assert((*parent) == 0);
653     if ((errorCode = GetClient(tcon, client)) != 0)
654         return(errorCode);
655     if (!(*client))
656         return(EINVAL);
657     assert(GetRights(*client, aCL, rights, anyrights) == 0);
658     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
659     if ((*targetptr)->disk.type != vDirectory) {
660         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
661         if ((*targetptr)->disk.owner == (*client)->ViceId)
662             (*rights) |= PRSFS_ADMINISTER;
663         else
664             (*rights) &= ~PRSFS_ADMINISTER;
665     }
666 #ifdef ADMIN_IMPLICIT_LOOKUP
667     /* admins get automatic lookup on everything */
668     if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
669 #endif /* ADMIN_IMPLICIT_LOOKUP */
670     return errorCode;
671
672 } /*GetVolumePackage*/
673
674
675 /*
676  * This is the opposite of GetVolumePackage(), and is always used at the end of
677  * AFS calls to put back all used vnodes and the volume in the proper order!
678  */
679 static afs_int32
680 PutVolumePackage(Vnode *parentwhentargetnotdir, 
681                  Vnode *targetptr,
682                  Vnode *parentptr,
683                  Volume *volptr)
684 {
685     int fileCode = 0;   /* Error code returned by the volume package */
686
687     if (parentwhentargetnotdir) {
688         VPutVnode(&fileCode, parentwhentargetnotdir);
689         assert(!fileCode || (fileCode == VSALVAGE));
690     }
691     if (targetptr) {
692         VPutVnode(&fileCode, targetptr);
693         assert(!fileCode || (fileCode == VSALVAGE));
694     }
695     if (parentptr) {
696         VPutVnode(&fileCode, parentptr);
697         assert(!fileCode || (fileCode == VSALVAGE));
698     }
699     if (volptr) {
700         VPutVolume(volptr);
701     }
702 } /*PutVolumePackage*/
703
704 static int VolumeOwner (register struct client *client, 
705                         register Vnode *targetptr)
706 {
707     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
708
709     if (owner >= 0)
710         return (client->ViceId == owner);
711     else {
712         /* 
713          * We don't have to check for host's cps since only regular
714          * viceid are volume owners.
715          */
716         return (acl_IsAMember(owner, &client->CPS));
717     }
718
719 } /*VolumeOwner*/
720
721 static int VolumeRootVnode (Vnode *targetptr)
722 {
723     return ((targetptr->vnodeNumber == ROOTVNODE) &&
724             (targetptr->disk.uniquifier == 1));
725
726 } /*VolumeRootVnode*/
727
728 /*
729  * Check if target file has the proper access permissions for the Fetch
730  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
731  * StoreStatus) related calls
732  */
733 /* this code should probably just set a "priv" flag where all the audit events
734  * are now, and only generate the audit event once at the end of the routine, 
735  * thus only generating the event if all the checks succeed, but only because
736  * of the privilege       XXX
737  */
738 static afs_int32
739 Check_PermissionRights(Vnode *targetptr,
740                        struct client *client,
741                        afs_int32 rights,
742                        int CallingRoutine,
743                        AFSStoreStatus *InStatus)
744 {
745     int errorCode = 0;
746 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
747 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
748 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
749
750     if (CallingRoutine & CHK_FETCH) {
751         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) 
752           {
753             if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
754                 if (   !(rights & PRSFS_LOOKUP)
755 #ifdef ADMIN_IMPLICIT_LOOKUP  
756                     /* grant admins fetch on all directories */
757                     && VanillaUser(client)
758 #endif /* ADMIN_IMPLICIT_LOOKUP */
759                     && !VolumeOwner(client, targetptr))
760                     return(EACCES);
761             } else {    /* file */
762                 /* must have read access, or be owner and have insert access */
763                 if (!(rights & PRSFS_READ) &&
764                     !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
765                     return(EACCES);
766             }
767             if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
768 #ifdef USE_GROUP_PERMS
769                 if (!OWNSp(client, targetptr) &&
770                     !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
771                     errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
772                                  ? 0: EACCES);
773                 } else {
774                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
775                                 ? 0: EACCES);
776                 }
777 #else
778                 /*
779                  * The check with the ownership below is a kludge to allow
780                  * reading of files created with no read permission. The owner
781                  * of the file is always allowed to read it.
782                  */
783                 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
784                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
785 #endif
786         }
787         else /*  !VanillaUser(client) && !FetchData */ {
788           osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
789                                         AUD_INT, CallingRoutine, AUD_END);
790         }
791     }
792     else { /* a store operation */
793       if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
794           && (CallingRoutine != CHK_STOREACL)
795           && (targetptr->disk.type == vFile))
796         {
797           /* bypass protection checks on first store after a create
798            * for the creator; also prevent chowns during this time
799            * unless you are a system administrator */
800           /******  InStatus->Owner && UnixModeBits better be SET!! */
801           if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
802             if (readonlyServer) 
803               return(VREADONLY);
804             else if (VanillaUser (client)) 
805               return(EPERM);      /* Was EACCES */
806             else
807               osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
808                                             AUD_INT, CallingRoutine, AUD_END);
809           }
810         } else {
811           if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
812             osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
813                                           AUD_INT, CallingRoutine, AUD_END);
814           }
815           else {
816             if (readonlyServer) {
817                 return(VREADONLY);
818             }
819             if (CallingRoutine == CHK_STOREACL) {
820               if (!(rights & PRSFS_ADMINISTER) &&
821                   !VolumeOwner(client, targetptr)) return(EACCES);
822             }
823             else {      /* store data or status */
824               /* watch for chowns and chgrps */
825               if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
826                 if (readonlyServer) 
827                   return(VREADONLY);
828                 else if (VanillaUser (client)) 
829                   return(EPERM);        /* Was EACCES */
830                 else
831                   osi_audit(PrivilegeEvent, 0,
832                             AUD_INT, (client ? client->ViceId : 0), 
833                             AUD_INT, CallingRoutine, AUD_END);
834               }
835               /* must be sysadmin to set suid/sgid bits */
836               if ((InStatus->Mask & AFS_SETMODE) &&
837 #ifdef AFS_NT40_ENV
838                   (InStatus->UnixModeBits & 0xc00) != 0) {
839 #else
840                   (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
841 #endif
842                 if (readonlyServer)
843                   return(VREADONLY);
844                 if (VanillaUser(client))
845                   return(EACCES);
846                 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
847                                               AUD_INT, CallingRoutine, AUD_END);
848               }
849               if (CallingRoutine == CHK_STOREDATA) {
850                 if (readonlyServer)
851                   return(VREADONLY);
852                 if (!(rights & PRSFS_WRITE))
853                   return(EACCES);
854                 /* Next thing is tricky.  We want to prevent people
855                  * from writing files sans 0200 bit, but we want
856                  * creating new files with 0444 mode to work.  We
857                  * don't check the 0200 bit in the "you are the owner"
858                  * path above, but here we check the bit.  However, if
859                  * you're a system administrator, we ignore the 0200
860                  * bit anyway, since you may have fchowned the file,
861                  * too */
862 #ifdef USE_GROUP_PERMS
863                         if ((targetptr->disk.type == vFile)
864                             && VanillaUser(client)) {
865                             if (!OWNSp(client, targetptr) &&
866                                 !acl_IsAMember(targetptr->disk.owner,
867                                                &client->CPS)) {
868                                 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
869                                              ? 0: EACCES);
870                             } else {
871                                 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
872                                              ? 0 : EACCES);
873                             }
874                         } else
875 #endif
876                 if ((targetptr->disk.type != vDirectory)
877                     && (!(targetptr->disk.modeBits & OWNERWRITE)))
878                   if (readonlyServer)
879                     return(VREADONLY);
880                   if (VanillaUser(client))
881                     return(EACCES);
882                   else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
883                                                      AUD_INT, CallingRoutine, AUD_END);
884               }
885               else {  /* a status store */
886                 if (readonlyServer)
887                   return(VREADONLY);
888                 if (targetptr->disk.type == vDirectory) {
889                   if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
890                     return(EACCES);
891                 }
892                 else {  /* a file  or symlink */
893                   if (!(rights & PRSFS_WRITE)) return(EACCES);
894                 }
895               }
896             }
897           }
898         }
899     }
900     return(errorCode);
901
902 } /*Check_PermissionRights*/
903
904
905 /*
906  * The Access List information is converted from its internal form in the
907  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
908  * external form and returned back to the caller, via the AccessList
909  * structure
910  */
911 static afs_int32
912 RXFetch_AccessList(Vnode *targetptr,
913                    Vnode *parentwhentargetnotdir,
914                    struct AFSOpaque *AccessList)
915 {
916     char * eACL;        /* External access list placeholder */
917
918     if (acl_Externalize((targetptr->disk.type == vDirectory ?
919                          VVnodeACL(targetptr) :
920                          VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
921         return EIO;
922     }
923     if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
924         acl_FreeExternalACL(&eACL);
925         return(E2BIG);
926     } else {
927         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
928         AccessList->AFSOpaque_len = strlen(eACL) +1;
929     }
930     acl_FreeExternalACL(&eACL);
931     return(0);
932
933 } /*RXFetch_AccessList*/
934
935
936 /*
937  * The Access List information is converted from its external form in the
938  * input AccessList structure to the internal representation and copied into
939  * the target dir's vnode storage.
940  */
941 static afs_int32
942 RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList)
943 {
944     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
945
946     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
947         return(EINVAL);
948     if ((newACL->size + 4) > VAclSize(targetptr))
949         return(E2BIG);
950     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
951     acl_FreeACL(&newACL);
952     return(0);
953
954 } /*RXStore_AccessList*/
955
956
957 static afs_int32
958 Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir,
959                  struct AFSAccessList *AccessList)
960 {
961     char * eACL;        /* External access list placeholder */
962
963     assert(acl_Externalize((targetptr->disk.type == vDirectory ?
964                             VVnodeACL(targetptr) :
965                             VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
966     if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
967         acl_FreeExternalACL(&eACL);
968         return(E2BIG);
969     } else {
970         strcpy((char *)(AccessList->SeqBody), (char *)eACL);
971         AccessList->SeqLen = strlen(eACL) +1;
972     }
973     acl_FreeExternalACL(&eACL);
974     return(0);
975
976 } /*Fetch_AccessList*/
977
978 /*
979  * The Access List information is converted from its external form in the
980  * input AccessList structure to the internal representation and copied into
981  * the target dir's vnode storage.
982  */
983 static afs_int32
984 Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList)
985 {
986     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
987
988     if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
989         return(EINVAL);
990     if ((newACL->size + 4) > VAclSize(targetptr))
991         return(E2BIG);
992     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
993     acl_FreeACL(&newACL);
994     return(0);
995
996 } /*Store_AccessList*/
997
998
999 /* In our current implementation, each successive data store (new file
1000  * data version) creates a new inode. This function creates the new
1001  * inode, copies the old inode's contents to the new one, remove the old
1002  * inode (i.e. decrement inode count -- if it's currently used the delete
1003  * will be delayed), and modify some fields (i.e. vnode's
1004  * disk.inodeNumber and cloned)
1005  */
1006 #define COPYBUFFSIZE    8192
1007 static int CopyOnWrite(Vnode *targetptr, Volume *volptr)
1008 {
1009     Inode       ino, nearInode;
1010     int         rdlen;
1011     int         wrlen;
1012     register int size, length;
1013     int ifd, ofd;
1014     char        *buff;
1015     int         rc;             /* return code */
1016     IHandle_t   *newH;  /* Use until finished copying, then cp to vnode.*/
1017     FdHandle_t  *targFdP;  /* Source Inode file handle */
1018     FdHandle_t  *newFdP; /* Dest Inode file handle */
1019
1020     if (targetptr->disk.type == vDirectory) DFlush();   /* just in case? */
1021
1022     size = targetptr->disk.length;
1023     buff = (char *)malloc(COPYBUFFSIZE);
1024     if (buff == NULL) {
1025         return EIO;
1026     }
1027
1028     ino = VN_GET_INO(targetptr);
1029     assert(VALID_INO(ino));
1030     targFdP = IH_OPEN(targetptr->handle);
1031     if (targFdP == NULL) {
1032         rc = errno;
1033         ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc));
1034         free(buff);
1035         VTakeOffline (volptr);
1036         return rc;
1037     }
1038
1039     nearInode = VN_GET_INO(targetptr);
1040     ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1041                     VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr),
1042                     targetptr->vnodeNumber, targetptr->disk.uniquifier,
1043                     (int)targetptr->disk.dataVersion);
1044     if (!VALID_INO(ino))
1045     {
1046         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));
1047         FDH_CLOSE(targFdP);
1048         free(buff);
1049         return ENOSPC;
1050     }
1051     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1052     newFdP = IH_OPEN(newH);
1053     assert(newFdP != NULL);
1054
1055     while(size > 0) {
1056         if (size > COPYBUFFSIZE) { /* more than a buffer */
1057             length = COPYBUFFSIZE;
1058             size -= COPYBUFFSIZE;
1059         } else {
1060             length = size;
1061             size = 0;
1062         }
1063         rdlen = FDH_READ(targFdP, buff, length); 
1064         if (rdlen == length)
1065             wrlen = FDH_WRITE(newFdP, buff, length);
1066         else
1067             wrlen = 0;
1068         /*  Callers of this function are not prepared to recover
1069          *  from error that put the filesystem in an inconsistent
1070          *  state. Make sure that we force the volume off-line if
1071          *  we some error other than ENOSPC - 4.29.99)
1072          *
1073          *  In case we are unable to write the required bytes, and the
1074          *  error code indicates that the disk is full, we roll-back to
1075          *  the initial state.
1076          */
1077         if((rdlen != length) || (wrlen != length))
1078                 if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */
1079                 {
1080                         ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1081                                         volptr->partition->name, V_id(volptr)));
1082                         /* remove destination inode which was partially copied till now*/
1083                         FDH_REALLYCLOSE(newFdP);
1084                         IH_RELEASE(newH);
1085                         FDH_REALLYCLOSE(targFdP);
1086                         rc = IH_DEC(V_linkHandle(volptr), ino,
1087                                   V_parentId(volptr));
1088                         if (!rc ) {
1089                             ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1090                                        rc, V_id(volptr), 
1091                                        volptr->partition->name));
1092                             VTakeOffline (volptr);
1093                         }
1094                         free(buff);
1095                         return ENOSPC;
1096                 }
1097                 else {
1098                     ViceLog(0,("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1099                                V_id(volptr), volptr->partition->name, length,
1100                                rdlen, wrlen, errno));
1101 #ifdef FAST_RESTART /* if running in no-salvage, don't core the server */
1102                     ViceLog(0,("CopyOnWrite failed: taking volume offline\n"));
1103 #else /* Avoid further corruption and try to get a core. */
1104                     assert(0); 
1105 #endif
1106                     /* Decrement this inode so salvager doesn't find it. */
1107                     FDH_REALLYCLOSE(newFdP);
1108                     IH_RELEASE(newH);
1109                     FDH_REALLYCLOSE(targFdP);
1110                     rc = IH_DEC(V_linkHandle(volptr), ino,
1111                                 V_parentId(volptr));
1112                     free(buff);
1113                     VTakeOffline (volptr);
1114                     return EIO;
1115                 }
1116 #ifndef AFS_PTHREAD_ENV
1117         IOMGR_Poll();
1118 #endif /* !AFS_PTHREAD_ENV */
1119     }
1120     FDH_REALLYCLOSE(targFdP);
1121     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1122               V_parentId(volptr)) ;
1123     assert(!rc);
1124     IH_RELEASE(targetptr->handle);
1125
1126     rc = FDH_SYNC(newFdP);
1127     assert(rc == 0);
1128     FDH_CLOSE(newFdP);
1129     targetptr->handle = newH;
1130     VN_SET_INO(targetptr, ino);
1131     targetptr->disk.cloned = 0;
1132     /* Internal change to vnode, no user level change to volume - def 5445 */
1133     targetptr->changed_oldTime = 1;
1134     free(buff);
1135     return 0;                           /* success */
1136 } /*CopyOnWrite*/
1137
1138
1139 /*
1140  * Common code to handle with removing the Name (file when it's called from
1141  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1142  * given directory, parentptr.
1143  */
1144 int DT1=0, DT0=0;
1145 static afs_int32
1146 DeleteTarget(Vnode *parentptr,
1147              Volume *volptr,
1148              Vnode **targetptr,
1149              DirHandle *dir,
1150              AFSFid *fileFid,
1151              char *Name,
1152              int ChkForDir)
1153 {
1154     DirHandle childdir;     /* Handle for dir package I/O */
1155     int errorCode = 0;
1156     int code;
1157
1158     /* watch for invalid names */
1159     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1160         return (EINVAL);
1161     if (parentptr->disk.cloned) 
1162     {
1163         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1164         if ((errorCode = CopyOnWrite(parentptr, volptr)))
1165         {
1166                 ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode));
1167                 return errorCode;
1168         }
1169     }
1170
1171     /* check that the file is in the directory */
1172     SetDirHandle(dir, parentptr);
1173     if (Lookup(dir, Name, fileFid))
1174         return(ENOENT);
1175     fileFid->Volume = V_id(volptr);
1176
1177     /* just-in-case check for something causing deadlock */
1178     if (fileFid->Vnode == parentptr->vnodeNumber)
1179         return(EINVAL);
1180
1181     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1182     if (errorCode) {
1183         return (errorCode);
1184     }
1185     if (ChkForDir == MustBeDIR) {
1186         if ((*targetptr)->disk.type != vDirectory)
1187             return(ENOTDIR);
1188     } else if ((*targetptr)->disk.type == vDirectory)
1189         return(EISDIR);
1190     
1191     /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/
1192     /**
1193       * If the uniquifiers dont match then instead of asserting
1194       * take the volume offline and return VSALVAGE
1195       */
1196     if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) {
1197         VTakeOffline(volptr);
1198         errorCode = VSALVAGE;
1199         return errorCode;
1200     }
1201         
1202     if (ChkForDir == MustBeDIR) {
1203         SetDirHandle(&childdir, *targetptr);
1204         if (IsEmpty(&childdir) != 0)
1205             return(EEXIST);
1206         DZap(&childdir);
1207         (*targetptr)->delete = 1;
1208     } else if ((--(*targetptr)->disk.linkCount) == 0) 
1209         (*targetptr)->delete = 1;
1210     if ((*targetptr)->delete) {
1211         if (VN_GET_INO(*targetptr)) {
1212             DT0++;
1213             IH_REALLYCLOSE((*targetptr)->handle);
1214             errorCode = IH_DEC(V_linkHandle(volptr),
1215                              VN_GET_INO(*targetptr),
1216                              V_parentId(volptr));
1217             IH_RELEASE((*targetptr)->handle);
1218             if (errorCode == -1) {
1219                 ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n",
1220                             PrintInode(NULL, VN_GET_INO(*targetptr)),
1221                             Name, errno));
1222 #ifdef  AFS_DEC_ENV
1223                 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
1224 #else
1225                 if (errno != ENOENT) 
1226 #endif
1227                     {
1228                     ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
1229                                 volptr->hashid));
1230                     VTakeOffline(volptr);
1231                     return (EIO);
1232                     }
1233                 DT1++;
1234                 errorCode = 0;
1235             }
1236         }
1237         VN_SET_INO(*targetptr, (Inode)0);
1238         VAdjustDiskUsage(&errorCode, volptr,
1239                         -(int)nBlocks((*targetptr)->disk.length), 0);
1240     }
1241     
1242     (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
1243
1244     code = Delete(dir,(char *) Name);
1245     if (code) {
1246        ViceLog(0, ("Error %d deleting %s\n", code,
1247                    (((*targetptr)->disk.type== Directory)?"directory":"file")));
1248        ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
1249                   volptr->hashid));
1250        VTakeOffline(volptr);
1251        if (!errorCode) errorCode = code;
1252     }
1253
1254     DFlush();
1255     return(errorCode);
1256
1257 } /*DeleteTarget*/
1258
1259
1260 /*
1261  * This routine updates the parent directory's status block after the
1262  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1263  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1264  * been performed.
1265  */
1266 static void
1267 Update_ParentVnodeStatus(Vnode *parentptr,
1268                          Volume *volptr,
1269                          DirHandle *dir,
1270                          int author,
1271                          int linkcount,
1272 #if FS_STATS_DETAILED
1273                          char a_inSameNetwork
1274 #endif /* FS_STATS_DETAILED */
1275                          )
1276 {
1277     afs_uint32 newlength;       /* Holds new directory length */
1278     int errorCode;
1279 #if FS_STATS_DETAILED
1280     Date currDate;              /*Current date*/
1281     int writeIdx;               /*Write index to bump*/
1282     int timeIdx;                /*Authorship time index to bump*/
1283 #endif /* FS_STATS_DETAILED */
1284
1285     parentptr->disk.dataVersion++;
1286     newlength = Length(dir);
1287     /* 
1288      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1289      * (create, symlink, link, makedir) so we need to check if we have enough space
1290      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1291      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1292      */
1293     if (nBlocks(newlength) != nBlocks(parentptr->disk.length))
1294         VAdjustDiskUsage(&errorCode, volptr, 
1295                          (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)),
1296                          (int)(nBlocks(newlength) - nBlocks(parentptr->disk.length)));
1297     parentptr->disk.length = newlength;
1298
1299 #if FS_STATS_DETAILED
1300     /*
1301      * Update directory write stats for this volume.  Note that the auth
1302      * counter is located immediately after its associated ``distance''
1303      * counter.
1304      */
1305     if (a_inSameNetwork)
1306         writeIdx = VOL_STATS_SAME_NET;
1307     else
1308         writeIdx = VOL_STATS_DIFF_NET;
1309     V_stat_writes(volptr, writeIdx)++;
1310     if (author != AnonymousID) {
1311         V_stat_writes(volptr, writeIdx+1)++;
1312     }
1313
1314     /*
1315      * Update the volume's authorship information in response to this
1316      * directory operation.  Get the current time, decide to which time
1317      * slot this operation belongs, and bump the appropriate slot.
1318      */
1319     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1320     timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1321                currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1322                currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1323                currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1324                currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1325                VOL_STATS_TIME_IDX_5);
1326     if (parentptr->disk.author == author) {
1327         V_stat_dirSameAuthor(volptr, timeIdx)++;
1328     }
1329     else {
1330         V_stat_dirDiffAuthor(volptr, timeIdx)++;
1331     }
1332 #endif /* FS_STATS_DETAILED */
1333
1334     parentptr->disk.author = author;
1335     parentptr->disk.linkCount = linkcount;
1336     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
1337     parentptr->disk.serverModifyTime = FT_ApproxTime();
1338     parentptr->changed_newTime = 1; /* vnode changed, write it back. */
1339 }
1340
1341
1342 /*
1343  * Update the target file's (or dir's) status block after the specified
1344  * operation is complete. Note that some other fields maybe updated by
1345  * the individual module.
1346  */
1347
1348 /* XXX INCOMPLETE - More attention is needed here! */
1349 static void
1350 Update_TargetVnodeStatus(Vnode *targetptr,
1351                          afs_uint32 Caller,
1352                          struct client *client,
1353                          AFSStoreStatus *InStatus,
1354                          Vnode *parentptr,
1355                          Volume *volptr,
1356                          afs_int32 length)
1357 {
1358 #if FS_STATS_DETAILED
1359     Date currDate;              /*Current date*/
1360     int writeIdx;               /*Write index to bump*/
1361     int timeIdx;                /*Authorship time index to bump*/
1362 #endif /* FS_STATS_DETAILED */
1363
1364     if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR))       {   /* initialize new file */
1365         targetptr->disk.parent = parentptr->vnodeNumber;
1366         targetptr->disk.length = length;
1367         /* targetptr->disk.group =      0;  save some cycles */
1368         targetptr->disk.modeBits = 0777;
1369         targetptr->disk.owner = client->ViceId;
1370         targetptr->disk.dataVersion =  0 ; /* consistent with the client */
1371         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1372         /* the inode was created in Alloc_NewVnode() */
1373     }
1374
1375 #if FS_STATS_DETAILED
1376     /*
1377      * Update file write stats for this volume.  Note that the auth
1378      * counter is located immediately after its associated ``distance''
1379      * counter.
1380      */
1381     if (client->InSameNetwork)
1382         writeIdx = VOL_STATS_SAME_NET;
1383     else
1384         writeIdx = VOL_STATS_DIFF_NET;
1385     V_stat_writes(volptr, writeIdx)++;
1386     if (client->ViceId != AnonymousID) {
1387         V_stat_writes(volptr, writeIdx+1)++;
1388     }
1389
1390     /*
1391      * We only count operations that DON'T involve creating new objects
1392      * (files, symlinks, directories) or simply setting status as
1393      * authorship-change operations.
1394      */
1395     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1396         /*
1397          * Update the volume's authorship information in response to this
1398          * file operation.  Get the current time, decide to which time
1399          * slot this operation belongs, and bump the appropriate slot.
1400          */
1401         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1402         timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1403                    currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1404                    currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1405                    currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1406                    currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1407                    VOL_STATS_TIME_IDX_5);
1408         if (targetptr->disk.author == client->ViceId) {
1409             V_stat_fileSameAuthor(volptr, timeIdx)++;
1410         } else {
1411             V_stat_fileDiffAuthor(volptr, timeIdx)++;
1412         }
1413       }
1414 #endif /* FS_STATS_DETAILED */
1415
1416     if (!(Caller & TVS_SSTATUS))
1417       targetptr->disk.author = client->ViceId;
1418     if (Caller & TVS_SDATA) {
1419       targetptr->disk.dataVersion++;
1420       if (VanillaUser(client))
1421         {
1422           targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1423 #ifdef CREATE_SGUID_ADMIN_ONLY
1424           targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1425 #endif
1426         }
1427     }
1428     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1429         /* store status, must explicitly request to change the date */
1430         if (InStatus->Mask & AFS_SETMODTIME)
1431             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1432     }
1433     else {/* other: date always changes, but perhaps to what is specified by caller */
1434         targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime());
1435     }
1436     if (InStatus->Mask & AFS_SETOWNER) {
1437         /* admin is allowed to do chmod, chown as well as chown, chmod. */
1438         if (VanillaUser(client))
1439           {
1440             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1441 #ifdef CREATE_SGUID_ADMIN_ONLY
1442             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1443 #endif
1444           }
1445         targetptr->disk.owner = InStatus->Owner;
1446         if (VolumeRootVnode (targetptr)) {
1447             Error errorCode = 0;        /* what should be done with this? */
1448
1449             V_owner(targetptr->volumePtr) = InStatus->Owner;
1450             VUpdateVolume(&errorCode, targetptr->volumePtr);
1451         }
1452     }
1453     if (InStatus->Mask & AFS_SETMODE) {
1454         int modebits = InStatus->UnixModeBits;
1455 #define CREATE_SGUID_ADMIN_ONLY 1
1456 #ifdef CREATE_SGUID_ADMIN_ONLY
1457         if (VanillaUser(client)) 
1458             modebits = modebits & 0777;
1459 #endif
1460         if (VanillaUser(client)) {
1461           targetptr->disk.modeBits = modebits;
1462         }
1463         else {
1464           targetptr->disk.modeBits = modebits;
1465           switch ( Caller ) {
1466           case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1467                                     AUD_INT, CHK_STOREDATA, AUD_END); break;
1468           case TVS_CFILE:
1469           case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1470                                     AUD_INT, CHK_STORESTATUS, AUD_END); break;
1471           default: break;
1472           }
1473         }
1474       }
1475     targetptr->disk.serverModifyTime = FT_ApproxTime();
1476     if (InStatus->Mask & AFS_SETGROUP)
1477         targetptr->disk.group = InStatus->Group;
1478     /* vnode changed : to be written back by VPutVnode */
1479     targetptr->changed_newTime = 1;
1480
1481 } /*Update_TargetVnodeStatus*/
1482
1483
1484 /*
1485  * Fills the CallBack structure with the expiration time and type of callback
1486  * structure. Warning: this function is currently incomplete.
1487  */
1488 static void
1489 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1490 {
1491     /* CallBackTime could not be 0 */
1492     if (CallBackTime == 0) {
1493         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1494         CallBack->ExpirationTime = 0;
1495     } else
1496         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();      
1497     CallBack->CallBackVersion = CALLBACK_VERSION;
1498     CallBack->CallBackType = CB_SHARED;             /* The default for now */
1499
1500 } /*SetCallBackStruct*/
1501
1502
1503 /*
1504  * Adjusts (Subtract) "length" number of blocks from the volume's disk
1505  * allocation; if some error occured (exceeded volume quota or partition
1506  * was full, or whatever), it frees the space back and returns the code.
1507  * We usually pre-adjust the volume space to make sure that there's
1508  * enough space before consuming some.
1509  */
1510 static afs_int32
1511 AdjustDiskUsage(Volume *volptr, afs_int32 length, afs_int32 checkLength)
1512 {
1513     int rc;
1514     int nc;
1515
1516     VAdjustDiskUsage(&rc, volptr, length, checkLength);
1517     if (rc) {
1518         VAdjustDiskUsage(&nc, volptr, -length, 0);
1519         if (rc == VOVERQUOTA) {
1520             ViceLog(2,("Volume %u (%s) is full\n",
1521                     V_id(volptr), V_name(volptr)));
1522             return(rc);
1523         }
1524         if (rc == VDISKFULL) {
1525             ViceLog(0,("Partition %s that contains volume %u is full\n",
1526                     volptr->partition->name, V_id(volptr)));
1527             return(rc);
1528         }
1529         ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc));
1530         return(rc);
1531     }
1532     return(0);
1533
1534 } /*AdjustDiskUsage*/
1535
1536 /*
1537  * Common code that handles the creation of a new file (SAFS_CreateFile and
1538  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1539  */
1540 static afs_int32
1541 Alloc_NewVnode(Vnode *parentptr,
1542                DirHandle *dir,
1543                Volume *volptr,
1544                Vnode **targetptr,
1545                char *Name,
1546                struct AFSFid *OutFid,
1547                int FileType,
1548                int BlocksPreallocatedForVnode)
1549 {
1550     int errorCode = 0;          /* Error code returned back */
1551     int temp;
1552     Inode inode=0;
1553     Inode nearInode;            /* hint for inode allocation in solaris */
1554
1555     if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1556                                     BlocksPreallocatedForVnode))) {
1557         ViceLog(25, ("Insufficient space to allocate %d blocks\n", 
1558                      BlocksPreallocatedForVnode));
1559         return(errorCode);
1560     }
1561
1562     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1563     if (errorCode != 0) {
1564         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
1565         return(errorCode);
1566     }
1567     OutFid->Volume = V_id(volptr);
1568     OutFid->Vnode = (*targetptr)->vnodeNumber;
1569     OutFid->Unique = (*targetptr)->disk.uniquifier;
1570
1571     nearInode = VN_GET_INO(parentptr);   /* parent is also in same vol */
1572
1573     /* create the inode now itself */
1574     inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1575                       VPartitionPath(V_partition(volptr)), nearInode,
1576                       V_id(volptr), (*targetptr)->vnodeNumber,
1577                       (*targetptr)->disk.uniquifier, 1);
1578
1579     /* error in creating inode */
1580     if (!VALID_INO(inode)) 
1581     {
1582                ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n", 
1583                          (*targetptr)->volumePtr->header->diskstuff.id,
1584                          (*targetptr)->vnodeNumber, 
1585                          errno));
1586                 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,0);
1587                 (*targetptr)->delete = 1; /* delete vnode */
1588                 return ENOSPC;
1589     }
1590     VN_SET_INO(*targetptr, inode);
1591     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1592
1593     /* copy group from parent dir */
1594     (*targetptr)->disk.group = parentptr->disk.group;
1595
1596     if (parentptr->disk.cloned) 
1597     {
1598         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1599         if ((errorCode = CopyOnWrite(parentptr, volptr)))  /* disk full */
1600         {
1601                 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1602                 /* delete the vnode previously allocated */
1603                 (*targetptr)->delete = 1;
1604                 VAdjustDiskUsage(&temp, volptr,
1605                                  -BlocksPreallocatedForVnode, 0);
1606                 IH_REALLYCLOSE((*targetptr)->handle);
1607                 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) )
1608                     ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1609                                 volptr->partition->name,
1610                                PrintInode(NULL, inode)));
1611                 IH_RELEASE((*targetptr)->handle);
1612                         
1613                 return errorCode;
1614         }
1615     }
1616     
1617     /* add the name to the directory */
1618     SetDirHandle(dir, parentptr);
1619     if ((errorCode = Create(dir,(char *)Name, OutFid))) {
1620         (*targetptr)->delete = 1;
1621         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode, 0);
1622         IH_REALLYCLOSE((*targetptr)->handle);
1623         if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1624             ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1625                        volptr->partition->name,
1626                        PrintInode(NULL, inode)));
1627         IH_RELEASE((*targetptr)->handle);
1628         return(errorCode);
1629     }
1630     DFlush();
1631     return(0);
1632
1633 } /*Alloc_NewVnode*/
1634
1635
1636 /*
1637  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1638  * SAFS_ReleaseLock)
1639  */
1640 static afs_int32
1641 HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType)
1642 {
1643     int Time;           /* Used for time */
1644     int writeVnode = targetptr->changed_oldTime; /* save original status */
1645
1646     /* Does the caller has Lock priviledges; root extends locks, however */
1647     if (LockingType != LockExtend && !(rights & PRSFS_LOCK))
1648         return(EACCES);
1649     targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
1650     Time = FT_ApproxTime();
1651     switch (LockingType) {
1652         case LockRead:
1653         case LockWrite:
1654             if (Time > targetptr->disk.lock.lockTime)
1655                 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0;
1656             Time += AFS_LOCKWAIT;
1657             if (LockingType == LockRead) {
1658                 if (targetptr->disk.lock.lockCount >= 0) {
1659                     ++(targetptr->disk.lock.lockCount);
1660                     targetptr->disk.lock.lockTime = Time;
1661                 } else return(EAGAIN);
1662             } else {
1663                 if (targetptr->disk.lock.lockCount == 0) {
1664                     targetptr->disk.lock.lockCount = -1;
1665                     targetptr->disk.lock.lockTime = Time;
1666                 } else return(EAGAIN);
1667             }
1668             break;
1669         case LockExtend:
1670             Time += AFS_LOCKWAIT;
1671             if (targetptr->disk.lock.lockCount != 0)
1672                 targetptr->disk.lock.lockTime = Time;
1673             else return(EINVAL);            
1674             break;
1675         case LockRelease:
1676             if ((--targetptr->disk.lock.lockCount) <= 0)
1677                 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0;
1678             break;
1679         default:
1680             targetptr->changed_oldTime = writeVnode; /* restore old status */
1681             ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1682     }
1683     return(0);
1684 } /*HandleLocking*/
1685
1686 /* 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. */
1687
1688 static afs_int32
1689 CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode)
1690 {
1691     if (readonlyServer)
1692         return(VREADONLY);
1693     if (!(rights & Prfs_Mode))
1694         return(EACCES);
1695     if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE)))
1696         return(EACCES);
1697     return(0);
1698 }
1699
1700 /*
1701  * If some flags (i.e. min or max quota) are set, the volume's in disk
1702  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1703  * update, if applicable.
1704  */
1705 static afs_int32
1706 RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus,
1707                       char *Name, char *OfflineMsg, char *Motd)
1708 {
1709     Error errorCode = 0;
1710
1711     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1712         V_minquota(volptr) = StoreVolStatus->MinQuota;
1713     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1714         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1715     if (strlen(OfflineMsg) > 0) {
1716         strcpy(V_offlineMessage(volptr), OfflineMsg);
1717     }
1718     if (strlen(Name) > 0) {
1719         strcpy(V_name(volptr), Name);
1720     }
1721 #if OPENAFS_VOL_STATS
1722     /*
1723      * We don't overwrite the motd field, since it's now being used
1724      * for stats
1725      */
1726 #else
1727     if (strlen(Motd) > 0) {
1728         strcpy(V_motd(volptr), Motd);
1729     }
1730 #endif /* FS_STATS_DETAILED */
1731     VUpdateVolume(&errorCode, volptr);
1732     return(errorCode);
1733
1734 } /*RXUpdate_VolumeStatus*/
1735
1736
1737 /* old interface */
1738 static afs_int32
1739 Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus,
1740                     struct BBS *Name, struct BBS *OfflineMsg,
1741                     struct BBS *Motd)
1742 {
1743     Error errorCode = 0;
1744
1745     if (StoreVolStatus->MinQuota > -1)
1746         V_minquota(volptr) = StoreVolStatus->MinQuota;
1747     if (StoreVolStatus->MaxQuota > -1)
1748         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1749     if (OfflineMsg->SeqLen > 1)
1750         strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody);
1751     if (Name->SeqLen > 1)
1752         strcpy(V_name(volptr), Name->SeqBody);
1753 #if OPENAFS_VOL_STATS
1754     /*
1755      * We don't overwrite the motd field, since it's now being used
1756      * for stats
1757      */
1758 #else
1759     if (Motd->SeqLen > 1)
1760         strcpy(V_motd(volptr), Motd->SeqBody);
1761 #endif /* FS_STATS_DETAILED */
1762     VUpdateVolume(&errorCode, volptr);
1763     return(errorCode);
1764
1765 } /*Update_VolumeStatus*/
1766
1767
1768 /*
1769  * Get internal volume-related statistics from the Volume disk label
1770  * structure and put it into the VolumeStatus structure, status; it's
1771  * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return
1772  * the volume status to the caller.
1773  */
1774 static afs_int32
1775 GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg,
1776                 struct BBS *motd, Volume *volptr)
1777 {
1778     status->Vid = V_id(volptr);
1779     status->ParentId = V_parentId(volptr);
1780     status->Online = V_inUse(volptr);
1781     status->InService = V_inService(volptr);
1782     status->Blessed = V_blessed(volptr);
1783     status->NeedsSalvage = V_needsSalvaged(volptr);
1784     if (VolumeWriteable(volptr))
1785         status->Type = ReadWrite;
1786     else
1787         status->Type = ReadOnly;
1788     status->MinQuota = V_minquota(volptr);
1789     status->MaxQuota = V_maxquota(volptr);
1790     status->BlocksInUse = V_diskused(volptr);
1791     status->PartBlocksAvail = volptr->partition->free;
1792     status->PartMaxBlocks = volptr->partition->totalUsable;
1793     strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
1794     name->SeqLen = strlen(V_name(volptr)) + 1;
1795     if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
1796     strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
1797     offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
1798     if (offMsg->SeqLen > offMsg->MaxSeqLen)
1799         offMsg->SeqLen = offMsg -> MaxSeqLen;
1800 #ifdef notdef
1801     /*Don't do anything with the motd field*/
1802     strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen);
1803     motd->SeqLen = strlen(nullString) + 1;
1804 #endif
1805     if (motd->SeqLen > motd->MaxSeqLen)
1806         motd->SeqLen = motd -> MaxSeqLen;
1807
1808 } /*GetVolumeStatus*/
1809
1810 static afs_int32
1811 RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg,
1812                   char **motd, Volume *volptr)
1813 {
1814     int temp;
1815
1816     status->Vid = V_id(volptr);
1817     status->ParentId = V_parentId(volptr);
1818     status->Online = V_inUse(volptr);
1819     status->InService = V_inService(volptr);
1820     status->Blessed = V_blessed(volptr);
1821     status->NeedsSalvage = V_needsSalvaged(volptr);
1822     if (VolumeWriteable(volptr))
1823         status->Type = ReadWrite;
1824     else
1825         status->Type = ReadOnly;
1826     status->MinQuota = V_minquota(volptr);
1827     status->MaxQuota = V_maxquota(volptr);
1828     status->BlocksInUse = V_diskused(volptr);
1829     status->PartBlocksAvail = volptr->partition->free;
1830     status->PartMaxBlocks = volptr->partition->totalUsable;
1831
1832     /* now allocate and copy these things; they're freed by the RXGEN stub */
1833     temp = strlen(V_name(volptr)) + 1;
1834     *name = malloc(temp);
1835     if (!*name) {
1836         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1837         assert(0);
1838     }
1839     strcpy(*name, V_name(volptr));
1840     temp = strlen(V_offlineMessage(volptr)) + 1;
1841     *offMsg = malloc(temp);
1842     if (!*offMsg) {
1843         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1844         assert(0);
1845     }
1846     strcpy(*offMsg, V_offlineMessage(volptr));
1847 #if OPENAFS_VOL_STATS
1848     *motd = malloc(1);
1849     if (!*motd) {
1850         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1851         assert(0);
1852     }
1853     strcpy(*motd, nullString);
1854 #else
1855     temp = strlen(V_motd(volptr)) + 1;
1856     *motd = malloc(temp);
1857     if (!*motd) {
1858         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1859         assert(0);
1860     }
1861     strcpy(*motd, V_motd(volptr));
1862 #endif /* FS_STATS_DETAILED */
1863
1864 } /*RXGetVolumeStatus*/
1865
1866
1867 static afs_int32
1868 FileNameOK(register char *aname)
1869 {
1870     register afs_int32 i, tc;
1871     i = strlen(aname);
1872     if (i >= 4) {
1873         /* watch for @sys on the right */
1874         if (strcmp(aname+i-4, "@sys") == 0) return 0;
1875     }
1876     while ((tc = *aname++)) {
1877         if (tc == '/') return 0;    /* very bad character to encounter */
1878     }
1879     return 1;   /* file name is ok */
1880
1881 } /*FileNameOK*/
1882
1883
1884 /* Debugging tool to print Volume Statu's contents */
1885 static void
1886 PrintVolumeStatus(VolumeStatus *status)
1887 {
1888     ViceLog(5,("Volume header contains:\n"));
1889     ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1890             status->Vid, status->ParentId, status->Online, status->InService,
1891             status->Blessed, status->NeedsSalvage));
1892     ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1893     ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1894             status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1895
1896 } /*PrintVolumeStatus*/
1897
1898
1899 /*
1900  * This variant of symlink is expressly to support the AFS/DFS translator
1901  * and is not supported by the AFS fileserver. We just return EINVAL.
1902  * The cache manager should not generate this call to an AFS cache manager.
1903  */
1904 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1905                              struct AFSFid *DirFid,
1906                              char *Name,
1907                              char *LinkContents,
1908                              struct AFSStoreStatus *InStatus,
1909                              struct AFSFid *OutFid,
1910                              struct AFSFetchStatus *OutFidStatus,
1911                              struct AFSFetchStatus *OutDirStatus,
1912                              struct AFSCallBack *CallBack,
1913                              struct AFSVolSync *Sync)
1914 {
1915     return EINVAL;
1916 }
1917
1918 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1919                                struct ResidencyCmdInputs *Inputs,
1920                                struct ResidencyCmdOutputs *Outputs)
1921 {
1922     return EINVAL;
1923 }
1924
1925 static struct afs_buffer {
1926     struct afs_buffer *next;
1927 } *freeBufferList = 0;
1928 static int afs_buffersAlloced = 0;
1929
1930 static FreeSendBuffer(register struct afs_buffer *adata)
1931 {
1932     FS_LOCK
1933     afs_buffersAlloced--;
1934     adata->next = freeBufferList;
1935     freeBufferList = adata;
1936     FS_UNLOCK
1937     return 0;
1938
1939 } /*FreeSendBuffer*/
1940
1941 /* allocate space for sender */
1942 static char *AllocSendBuffer()
1943 {
1944     register struct afs_buffer *tp;
1945
1946     FS_LOCK
1947     afs_buffersAlloced++;
1948     if (!freeBufferList) {
1949         char *tmp;
1950         FS_UNLOCK
1951
1952         tmp = malloc(sendBufSize);
1953         if (!tmp) {
1954             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1955             assert(0);
1956         }
1957         return tmp;
1958     }
1959     tp = freeBufferList;
1960     freeBufferList = tp->next;
1961     FS_UNLOCK
1962     return (char *) tp;
1963
1964 } /*AllocSendBuffer*/
1965
1966 /*
1967  * This routine returns the status info associated with the targetptr vnode
1968  * in the AFSFetchStatus structure.  Some of the newer fields, such as
1969  * SegSize and Group are not yet implemented
1970  */
1971 static 
1972 void GetStatus(Vnode *targetptr,
1973                AFSFetchStatus *status,
1974                afs_int32 rights,
1975                afs_int32 anyrights,
1976                Vnode *parentptr)
1977 {
1978     /* initialize return status from a vnode  */
1979     status->InterfaceVersion = 1;
1980     status->SyncCounter = status->dataVersionHigh = status->lockCount =
1981     status->errorCode = 0;
1982     status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1983     if (targetptr->disk.type == vFile)
1984         status->FileType = File;
1985     else if (targetptr->disk.type == vDirectory)
1986         status->FileType = Directory;
1987     else if (targetptr->disk.type == vSymlink)
1988         status->FileType = SymbolicLink;
1989     else
1990         status->FileType = Invalid;                     /*invalid type field */
1991     status->LinkCount = targetptr->disk.linkCount;
1992     status->Length_hi = 0;
1993     status->Length = targetptr->disk.length;
1994     status->DataVersion = targetptr->disk.dataVersion;
1995     status->Author = targetptr->disk.author;
1996     status->Owner = targetptr->disk.owner;
1997     status->CallerAccess = rights;
1998     status->AnonymousAccess = anyrights;
1999     status->UnixModeBits = targetptr->disk.modeBits;
2000     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2001     status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2002     status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2003     status->ServerModTime = targetptr->disk.serverModifyTime;                   
2004     status->Group = targetptr->disk.group;
2005     status->lockCount = targetptr->disk.lock.lockCount;
2006     status->errorCode = 0;
2007
2008 } /*GetStatus*/
2009
2010 static
2011 afs_int32 common_FetchData64 (struct rx_call *acall, 
2012                               struct AFSFid *Fid,    
2013                               afs_int32 Pos,         
2014                               afs_int32 Len,         
2015                               struct AFSFetchStatus *OutStatus,
2016                               struct AFSCallBack *CallBack,
2017                               struct AFSVolSync *Sync,
2018                               int type)              
2019
2020     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
2021     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
2022     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
2023     int     errorCode = 0;                  /* return code to caller */
2024     int     fileCode =  0;                  /* return code from vol package */
2025     Volume * volptr = 0;                    /* pointer to the volume */
2026     struct client *client;                  /* pointer to the client data */
2027     struct rx_connection *tcon;             /* the connection we're part of */
2028     afs_int32 rights, anyrights;                    /* rights for this and any user */
2029     struct client *t_client;                /* tmp ptr to client data */
2030     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2031 #if FS_STATS_DETAILED
2032     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2033     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2034     struct timeval opStartTime,
2035                    opStopTime;              /* Start/stop times for RPC op*/
2036     struct timeval xferStartTime,
2037                    xferStopTime;            /* Start/stop times for xfer portion*/
2038     struct timeval elapsedTime;             /* Transfer time */
2039     afs_int32 bytesToXfer;                          /* # bytes to xfer*/
2040     afs_int32 bytesXferred;                         /* # bytes actually xferred*/
2041     int readIdx;                            /* Index of read stats array to bump*/
2042     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2043
2044     /*
2045      * Set our stats pointers, remember when the RPC operation started, and
2046      * tally the operation.
2047      */
2048     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2049     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2050     FS_LOCK
2051     (opP->numOps)++;
2052     FS_UNLOCK
2053     TM_GetTimeOfDay(&opStartTime, 0);
2054 #endif /* FS_STATS_DETAILED */
2055
2056     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2057             Fid->Volume, Fid->Vnode, Fid->Unique));     
2058     FS_LOCK
2059     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2060     FS_UNLOCK
2061
2062     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2063         goto Bad_FetchData;
2064
2065     /* Get ptr to client data for user Id for logging */
2066     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2067     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2068     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2069             Fid->Volume, Fid->Vnode, Fid->Unique,
2070             inet_ntoa(logHostAddr), t_client->ViceId)); 
2071     /*
2072      * Get volume/vnode for the fetched file; caller's access rights to
2073      * it are also returned
2074      */
2075     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2076                                      DONTCHECK, &parentwhentargetnotdir,
2077                                      &client, READ_LOCK, &rights, &anyrights)))
2078         goto Bad_FetchData;
2079
2080     SetVolumeSync(Sync, volptr);
2081
2082 #if FS_STATS_DETAILED
2083     /*
2084      * Remember that another read operation was performed.
2085      */
2086     FS_LOCK
2087     if (client->InSameNetwork)
2088         readIdx = VOL_STATS_SAME_NET;
2089     else
2090         readIdx = VOL_STATS_DIFF_NET;
2091     V_stat_reads(volptr, readIdx)++;
2092     if (client->ViceId != AnonymousID) {
2093         V_stat_reads(volptr, readIdx+1)++;
2094     }
2095     FS_UNLOCK
2096 #endif /* FS_STATS_DETAILED */
2097
2098     /* Check whether the caller has permission access to fetch the data */
2099     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2100                                            CHK_FETCHDATA, 0))) 
2101         goto Bad_FetchData;
2102
2103     /*
2104      * Drop the read lock on the parent directory after saving the parent
2105      * vnode information we need to pass to GetStatus
2106      */
2107     if (parentwhentargetnotdir != NULL) {
2108         tparentwhentargetnotdir = *parentwhentargetnotdir;
2109         VPutVnode(&fileCode, parentwhentargetnotdir);
2110         assert(!fileCode || (fileCode == VSALVAGE));
2111         parentwhentargetnotdir = NULL;
2112     }
2113
2114 #if FS_STATS_DETAILED
2115     /*
2116      * Remember when the data transfer started.
2117      */
2118     TM_GetTimeOfDay(&xferStartTime, 0);
2119 #endif /* FS_STATS_DETAILED */
2120
2121     /* actually do the data transfer */
2122 #if FS_STATS_DETAILED
2123     errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2124                                   &bytesToXfer, &bytesXferred);
2125 #else
2126     if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2127         goto Bad_FetchData;
2128 #endif /* FS_STATS_DETAILED */
2129
2130 #if FS_STATS_DETAILED
2131     /*
2132      * At this point, the data transfer is done, for good or ill.  Remember
2133      * when the transfer ended, bump the number of successes/failures, and
2134      * integrate the transfer size and elapsed time into the stats.  If the
2135      * operation failed, we jump to the appropriate point.
2136      */
2137     TM_GetTimeOfDay(&xferStopTime, 0);
2138     FS_LOCK
2139     (xferP->numXfers)++;
2140     if (!errorCode) {
2141         (xferP->numSuccesses)++;
2142
2143         /*
2144          * Bump the xfer sum by the number of bytes actually sent, NOT the
2145          * target number.
2146          */
2147         tot_bytesXferred += bytesXferred;
2148         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2149         tot_bytesXferred &= 0x3FF;
2150         if (bytesXferred < xferP->minBytes)
2151             xferP->minBytes = bytesXferred;
2152         if (bytesXferred > xferP->maxBytes)
2153             xferP->maxBytes = bytesXferred;
2154
2155         /*
2156          * Tally the size of the object.  Note: we tally the actual size,
2157          * NOT the number of bytes that made it out over the wire.
2158          */
2159         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2160             (xferP->count[0])++;
2161         else
2162             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2163                 (xferP->count[1])++;
2164         else
2165             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2166                 (xferP->count[2])++;
2167         else
2168             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2169                 (xferP->count[3])++;
2170         else
2171             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2172                 (xferP->count[4])++;
2173         else
2174             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2175                 (xferP->count[5])++;
2176         else
2177             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2178                 (xferP->count[6])++;
2179         else
2180             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2181                 (xferP->count[7])++;
2182         else
2183             (xferP->count[8])++;
2184
2185         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2186         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2187         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2188         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2189             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2190         }
2191         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2192             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2193         }
2194       }
2195     FS_UNLOCK
2196     /*
2197      * Finally, go off to tell our caller the bad news in case the
2198      * fetch failed.
2199      */
2200     if (errorCode)
2201         goto Bad_FetchData;
2202 #endif /* FS_STATS_DETAILED */
2203
2204     /* write back  the OutStatus from the target vnode  */
2205     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2206
2207     /* if a r/w volume, promise a callback to the caller */
2208     if (VolumeWriteable(volptr))
2209         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2210     else {
2211       struct AFSFid myFid;              
2212       memset(&myFid, 0, sizeof(struct AFSFid));
2213       myFid.Volume = Fid->Volume;
2214       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2215       }
2216
2217 Bad_FetchData: 
2218     /* Update and store volume/vnode and parent vnodes back */
2219     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2220     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
2221     errorCode = CallPostamble(tcon, errorCode);
2222
2223 #if FS_STATS_DETAILED
2224     TM_GetTimeOfDay(&opStopTime, 0);
2225     if (errorCode == 0) {
2226         FS_LOCK
2227         (opP->numSuccesses)++;
2228         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2229         fs_stats_AddTo((opP->sumTime), elapsedTime);
2230         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2231         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2232             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2233         }
2234         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2235             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2236         }
2237         FS_UNLOCK
2238       }
2239
2240 #endif /* FS_STATS_DETAILED */
2241
2242     osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2243     return(errorCode);
2244
2245 } /*SRXAFS_FetchData*/
2246
2247 afs_int32 SRXAFS_FetchData (struct rx_call *acall,   
2248                             struct AFSFid *Fid,      
2249                             afs_int32 Pos,           
2250                             afs_int32 Len,           
2251                             struct AFSFetchStatus *OutStatus,
2252                             struct AFSCallBack *CallBack, 
2253                             struct AFSVolSync *Sync) 
2254
2255 {
2256     int code;
2257
2258     code = common_FetchData64 (acall, Fid, Pos, Len, OutStatus,
2259                              CallBack, Sync, 0);
2260     return code;
2261 }
2262
2263 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall, 
2264                               struct AFSFid *Fid,    
2265                               afs_int64 Pos,         
2266                               afs_int64 Len,         
2267                               struct AFSFetchStatus *OutStatus,
2268                               struct AFSCallBack *CallBack,
2269                               struct AFSVolSync *Sync)
2270 {
2271     int code;
2272     afs_int32 tPos, tLen;
2273
2274 #ifdef AFS_64BIT_ENV
2275     if (Pos + Len > 0x7fffffff)
2276         return E2BIG;
2277     tPos = Pos;
2278     tLen = Len;
2279 #else /* AFS_64BIT_ENV */
2280     if (Pos.high || Len.high)
2281         return E2BIG;
2282     tPos = Pos.low;
2283     tLen = Len.low;
2284 #endif /* AFS_64BIT_ENV */
2285
2286     code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2287                              CallBack, Sync, 1);
2288     return code;
2289 }
2290
2291 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,    
2292                            struct AFSFid *Fid,       
2293                            struct AFSOpaque *AccessList,     
2294                            struct AFSFetchStatus *OutStatus, 
2295                            struct AFSVolSync *Sync)
2296 {
2297     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2298     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2299     int     errorCode = 0;              /* return error code to caller */
2300     Volume * volptr = 0;                /* pointer to the volume */
2301     struct client *client;              /* pointer to the client data */
2302     afs_int32 rights, anyrights;                /* rights for this and any user */
2303     struct rx_connection *tcon = rx_ConnectionOf(acall);
2304     struct client *t_client;                /* tmp ptr to client data */
2305     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2306 #if FS_STATS_DETAILED
2307     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2308     struct timeval opStartTime,
2309                    opStopTime;              /* Start/stop times for RPC op*/
2310     struct timeval elapsedTime;             /* Transfer time */
2311
2312     /*
2313      * Set our stats pointer, remember when the RPC operation started, and
2314      * tally the operation.
2315      */
2316     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2317     FS_LOCK
2318     (opP->numOps)++;
2319     FS_UNLOCK
2320     TM_GetTimeOfDay(&opStartTime, 0);
2321 #endif /* FS_STATS_DETAILED */
2322
2323     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2324             Fid->Volume, Fid->Vnode, Fid->Unique));
2325     FS_LOCK
2326     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2327     FS_UNLOCK
2328     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2329         goto Bad_FetchACL;
2330
2331     /* Get ptr to client data for user Id for logging */
2332     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2333     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2334     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2335             Fid->Volume, Fid->Vnode, Fid->Unique,
2336             inet_ntoa(logHostAddr), t_client->ViceId));
2337
2338     AccessList->AFSOpaque_len = 0;
2339     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2340     if (!AccessList->AFSOpaque_val) {
2341         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2342         assert(0);
2343     }
2344
2345     /*
2346      * Get volume/vnode for the fetched file; caller's access rights to it
2347      * are also returned
2348      */
2349     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2350                                      DONTCHECK, &parentwhentargetnotdir,
2351                                      &client, READ_LOCK, &rights, &anyrights)))
2352         goto Bad_FetchACL;
2353
2354     SetVolumeSync(Sync, volptr);
2355
2356     /* Check whether we have permission to fetch the ACL */
2357     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2358                                            CHK_FETCHACL, 0)))
2359         goto Bad_FetchACL;
2360
2361     /* Get the Access List from the dir's vnode */
2362     if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2363                                        AccessList)))
2364         goto Bad_FetchACL;
2365
2366     /* Get OutStatus back From the target Vnode  */
2367     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2368
2369 Bad_FetchACL: 
2370     /* Update and store volume/vnode and parent vnodes back */
2371     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2372     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2373             errorCode, AccessList->AFSOpaque_val));
2374     errorCode = CallPostamble(tcon, errorCode);
2375
2376 #if FS_STATS_DETAILED
2377     TM_GetTimeOfDay(&opStopTime, 0);
2378     if (errorCode == 0) {
2379         FS_LOCK
2380         (opP->numSuccesses)++;
2381         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2382         fs_stats_AddTo((opP->sumTime), elapsedTime);
2383         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2384         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2385             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2386         }
2387         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2388             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2389         }
2390         FS_UNLOCK
2391       }
2392
2393 #endif /* FS_STATS_DETAILED */
2394
2395     osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2396     return errorCode;
2397 } /*SRXAFS_FetchACL*/
2398
2399
2400 /*
2401  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2402  * merged into it when possible.
2403  */
2404 static 
2405 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2406                              struct AFSFid *Fid,  
2407                              struct AFSFetchStatus *OutStatus,
2408                              struct AFSCallBack *CallBack,      
2409                              struct AFSVolSync *Sync)           
2410 {
2411     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2412     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2413     int     errorCode = 0;              /* return code to caller */
2414     Volume * volptr = 0;                /* pointer to the volume */
2415     struct client *client;              /* pointer to the client data */
2416     afs_int32 rights, anyrights;                /* rights for this and any user */
2417     struct client *t_client;            /* tmp ptr to client data */
2418     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2419     struct rx_connection *tcon = rx_ConnectionOf(acall);
2420
2421     /* Get ptr to client data for user Id for logging */
2422     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2423     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2424     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
2425             Fid->Volume, Fid->Vnode, Fid->Unique,
2426             inet_ntoa(logHostAddr), t_client->ViceId));
2427     FS_LOCK
2428     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2429     FS_UNLOCK
2430     /*
2431      * Get volume/vnode for the fetched file; caller's rights to it are
2432      * also returned
2433      */
2434     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2435                                      DONTCHECK, &parentwhentargetnotdir,
2436                                      &client, READ_LOCK, &rights, &anyrights)))
2437         goto Bad_FetchStatus;
2438
2439     /* set volume synchronization information */
2440     SetVolumeSync(Sync, volptr);
2441
2442     /* Are we allowed to fetch Fid's status? */
2443     if (targetptr->disk.type != vDirectory) {
2444       if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2445                                              CHK_FETCHSTATUS, 0))) {
2446           if (rx_GetCallAbortCode(acall) == errorCode) 
2447               rx_SetCallAbortCode(acall, 0);
2448           goto Bad_FetchStatus;
2449       }
2450     }
2451
2452     /* set OutStatus From the Fid  */
2453     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2454
2455     /* If a r/w volume, also set the CallBack state */
2456     if (VolumeWriteable(volptr))
2457         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2458     else {
2459       struct AFSFid myFid;              
2460       memset(&myFid, 0, sizeof(struct AFSFid));
2461       myFid.Volume = Fid->Volume;
2462       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2463       }
2464
2465 Bad_FetchStatus: 
2466     /* Update and store volume/vnode and parent vnodes back */
2467     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2468     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
2469     return errorCode;
2470
2471 } /*SAFSS_FetchStatus*/
2472
2473
2474 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2475                             struct AFSCBFids *Fids,
2476                             struct AFSBulkStats *OutStats,
2477                             struct AFSCBs *CallBacks,
2478                             struct AFSVolSync *Sync)
2479 {
2480     register int i;
2481     afs_int32 nfiles;
2482     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2483     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2484     int     errorCode = 0;              /* return code to caller */
2485     Volume * volptr = 0;                /* pointer to the volume */
2486     struct client *client;              /* pointer to the client data */
2487     afs_int32 rights, anyrights;                /* rights for this and any user */
2488     register struct AFSFid *tfid;       /* file id we're dealing with now */
2489     struct rx_connection *tcon = rx_ConnectionOf(acall);
2490 #if FS_STATS_DETAILED
2491     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2492     struct timeval opStartTime,
2493                    opStopTime;              /* Start/stop times for RPC op*/
2494     struct timeval elapsedTime;             /* Transfer time */
2495
2496     /*
2497      * Set our stats pointer, remember when the RPC operation started, and
2498      * tally the operation.
2499      */
2500     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2501     FS_LOCK
2502     (opP->numOps)++;
2503     FS_UNLOCK
2504     TM_GetTimeOfDay(&opStartTime, 0);
2505 #endif /* FS_STATS_DETAILED */
2506
2507     ViceLog(1, ("SAFS_BulkStatus\n"));
2508     FS_LOCK
2509     AFSCallStats.TotalCalls++;
2510     FS_UNLOCK
2511
2512     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2513     if (nfiles <= 0) {                  /* Sanity check */
2514         errorCode = EINVAL;
2515         goto Audit_and_Return;
2516     }
2517
2518     /* allocate space for return output parameters */
2519     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2520         malloc(nfiles * sizeof(struct AFSFetchStatus));
2521     if (!OutStats->AFSBulkStats_val) {
2522         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2523         assert(0);
2524     }
2525     OutStats->AFSBulkStats_len = nfiles;
2526     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2527         malloc(nfiles * sizeof(struct AFSCallBack));
2528     if (!CallBacks->AFSCBs_val) {
2529         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2530         assert(0);
2531     }
2532     CallBacks->AFSCBs_len = nfiles;
2533
2534     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2535         goto Bad_BulkStatus;
2536
2537     tfid = Fids->AFSCBFids_val;
2538     for (i=0; i<nfiles; i++, tfid++) {
2539         /*
2540          * Get volume/vnode for the fetched file; caller's rights to it
2541          * are also returned
2542          */
2543         if ((errorCode =
2544             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2545                              DONTCHECK, &parentwhentargetnotdir, &client,
2546                              READ_LOCK, &rights, &anyrights)))
2547                 goto Bad_BulkStatus;
2548         /* set volume synchronization information, but only once per call */
2549         if (i == nfiles)
2550             SetVolumeSync(Sync, volptr);
2551
2552         /* Are we allowed to fetch Fid's status? */
2553         if (targetptr->disk.type != vDirectory) {
2554             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2555                                                    CHK_FETCHSTATUS, 0))) {
2556                 if (rx_GetCallAbortCode(acall) == errorCode) 
2557                     rx_SetCallAbortCode(acall, 0);
2558                 goto Bad_BulkStatus;
2559             }
2560         }
2561
2562         /* set OutStatus From the Fid  */
2563         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2564                   rights, anyrights, parentwhentargetnotdir);
2565
2566         /* If a r/w volume, also set the CallBack state */
2567         if (VolumeWriteable(volptr))
2568             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2569                               &CallBacks->AFSCBs_val[i]);
2570         else {
2571           struct AFSFid myFid;          
2572           memset(&myFid, 0, sizeof(struct AFSFid));
2573           myFid.Volume = tfid->Volume;
2574           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2575                               &CallBacks->AFSCBs_val[i]);
2576         }
2577
2578         /* put back the file ID and volume */
2579         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2580         parentwhentargetnotdir = (Vnode *) 0;
2581         targetptr = (Vnode *) 0;
2582         volptr = (Volume *) 0;
2583     }
2584
2585 Bad_BulkStatus: 
2586     /* Update and store volume/vnode and parent vnodes back */
2587     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2588     errorCode = CallPostamble(tcon, errorCode);
2589
2590 #if FS_STATS_DETAILED
2591     TM_GetTimeOfDay(&opStopTime, 0);
2592     if (errorCode == 0) {
2593         FS_LOCK
2594         (opP->numSuccesses)++;
2595         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2596         fs_stats_AddTo((opP->sumTime), elapsedTime);
2597         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2598         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2599             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2600         }
2601         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2602             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2603         }
2604         FS_UNLOCK
2605     }   
2606
2607 #endif /* FS_STATS_DETAILED */
2608
2609 Audit_and_Return:
2610     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
2611     osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2612     return errorCode;
2613
2614 } /*SRXAFS_BulkStatus*/
2615
2616
2617 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2618                                   struct AFSCBFids *Fids,
2619                                   struct AFSBulkStats *OutStats,
2620                                   struct AFSCBs *CallBacks,
2621                                   struct AFSVolSync *Sync)
2622 {
2623     register int i;
2624     afs_int32 nfiles;
2625     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2626     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2627     int     errorCode = 0;              /* return code to caller */
2628     Volume * volptr = 0;                /* pointer to the volume */
2629     struct client *client;              /* pointer to the client data */
2630     afs_int32 rights, anyrights;                /* rights for this and any user */
2631     register struct AFSFid *tfid;       /* file id we're dealing with now */
2632     struct rx_connection *tcon;
2633     AFSFetchStatus *tstatus;
2634 #if FS_STATS_DETAILED
2635     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2636     struct timeval opStartTime,
2637                    opStopTime;              /* Start/stop times for RPC op*/
2638     struct timeval elapsedTime;             /* Transfer time */
2639
2640     /*
2641      * Set our stats pointer, remember when the RPC operation started, and
2642      * tally the operation.
2643      */
2644     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2645     FS_LOCK
2646     (opP->numOps)++;
2647     FS_UNLOCK
2648     TM_GetTimeOfDay(&opStartTime, 0);
2649 #endif /* FS_STATS_DETAILED */
2650
2651     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2652     FS_LOCK
2653     AFSCallStats.TotalCalls++;
2654     FS_UNLOCK
2655
2656     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2657     if (nfiles <= 0) {                  /* Sanity check */
2658         errorCode = EINVAL;
2659         goto Audit_and_Return;
2660     }
2661
2662     /* allocate space for return output parameters */
2663     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2664         malloc(nfiles * sizeof(struct AFSFetchStatus));
2665     if (!OutStats->AFSBulkStats_val) {
2666         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2667         assert(0);
2668     }
2669     OutStats->AFSBulkStats_len = nfiles;
2670     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2671         malloc(nfiles * sizeof(struct AFSCallBack));
2672     if (!CallBacks->AFSCBs_val) {
2673         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2674         assert(0);
2675     }
2676     CallBacks->AFSCBs_len = nfiles;
2677
2678     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2679         goto Bad_InlineBulkStatus;
2680     }
2681
2682     tfid = Fids->AFSCBFids_val;
2683     for (i=0; i<nfiles; i++, tfid++) {
2684         /*
2685          * Get volume/vnode for the fetched file; caller's rights to it
2686          * are also returned
2687          */
2688         if ((errorCode =
2689             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2690                              DONTCHECK, &parentwhentargetnotdir, &client,
2691                              READ_LOCK, &rights, &anyrights))) {
2692             tstatus = &OutStats->AFSBulkStats_val[i];
2693             tstatus->errorCode = errorCode;
2694             parentwhentargetnotdir = (Vnode *) 0;
2695             targetptr = (Vnode *) 0;
2696             volptr = (Volume *) 0;
2697             continue;
2698         }
2699
2700         /* set volume synchronization information, but only once per call */
2701         if (i == nfiles)
2702             SetVolumeSync(Sync, volptr);
2703
2704         /* Are we allowed to fetch Fid's status? */
2705         if (targetptr->disk.type != vDirectory) {
2706             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2707                                                    CHK_FETCHSTATUS, 0))) {
2708                 tstatus = &OutStats->AFSBulkStats_val[i];
2709                 tstatus->errorCode = errorCode;
2710                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2711                 parentwhentargetnotdir = (Vnode *) 0;
2712                 targetptr = (Vnode *) 0;
2713                 volptr = (Volume *) 0;
2714                 continue;
2715             }
2716         }
2717
2718         /* set OutStatus From the Fid  */
2719         GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], 
2720           rights, anyrights, parentwhentargetnotdir);
2721
2722         /* If a r/w volume, also set the CallBack state */
2723         if (VolumeWriteable(volptr))
2724             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2725                               &CallBacks->AFSCBs_val[i]);
2726         else {
2727           struct AFSFid myFid;          
2728           memset(&myFid, 0, sizeof(struct AFSFid));
2729           myFid.Volume = tfid->Volume;
2730           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2731                               &CallBacks->AFSCBs_val[i]);
2732         }
2733
2734         /* put back the file ID and volume */
2735         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2736         parentwhentargetnotdir = (Vnode *) 0;
2737         targetptr = (Vnode *) 0;
2738         volptr = (Volume *) 0;
2739     }
2740
2741 Bad_InlineBulkStatus: 
2742     /* Update and store volume/vnode and parent vnodes back */
2743     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2744     errorCode = CallPostamble(tcon, errorCode);
2745
2746 #if FS_STATS_DETAILED
2747     TM_GetTimeOfDay(&opStopTime, 0);
2748     if (errorCode == 0) {
2749         FS_LOCK
2750         (opP->numSuccesses)++;
2751         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2752         fs_stats_AddTo((opP->sumTime), elapsedTime);
2753         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2754         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2755             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2756         }
2757         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2758             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2759         }
2760         FS_UNLOCK
2761     }   
2762
2763 #endif /* FS_STATS_DETAILED */
2764
2765 Audit_and_Return:
2766     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
2767     osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2768     return 0;
2769
2770 } /*SRXAFS_InlineBulkStatus*/
2771
2772
2773 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,            
2774                               struct AFSFid *Fid,               
2775                               struct AFSFetchStatus *OutStatus, 
2776                               struct AFSCallBack *CallBack,     
2777                               struct AFSVolSync *Sync)
2778 {
2779     afs_int32 code;
2780     struct rx_connection *tcon;
2781 #if FS_STATS_DETAILED
2782     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2783     struct timeval opStartTime,
2784                    opStopTime;              /* Start/stop times for RPC op*/
2785     struct timeval elapsedTime;             /* Transfer time */
2786
2787     /*
2788      * Set our stats pointer, remember when the RPC operation started, and
2789      * tally the operation.
2790      */
2791     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2792     FS_LOCK
2793     (opP->numOps)++;
2794     FS_UNLOCK
2795     TM_GetTimeOfDay(&opStartTime, 0);
2796 #endif /* FS_STATS_DETAILED */
2797
2798     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2799         goto Bad_FetchStatus;
2800
2801     code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2802
2803 Bad_FetchStatus:    
2804     code = CallPostamble(tcon, code);
2805
2806 #if FS_STATS_DETAILED
2807     TM_GetTimeOfDay(&opStopTime, 0);
2808     if (code == 0) {
2809         FS_LOCK
2810         (opP->numSuccesses)++;
2811         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2812         fs_stats_AddTo((opP->sumTime), elapsedTime);
2813         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2814         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2815             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2816         }
2817         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2818             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2819         }
2820         FS_UNLOCK
2821       }
2822
2823 #endif /* FS_STATS_DETAILED */
2824
2825     osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2826     return code;
2827
2828 } /*SRXAFS_FetchStatus*/
2829
2830
2831 afs_int32 SRXAFS_StoreData (struct rx_call *acall,              
2832                             struct AFSFid *Fid,                 
2833                             struct AFSStoreStatus *InStatus,    
2834                             afs_uint32 Pos,                     
2835                             afs_uint32 Length,                  
2836                             afs_uint32 FileLength,              
2837                             struct AFSFetchStatus *OutStatus,   
2838                             struct AFSVolSync *Sync)
2839 {
2840     Vnode * targetptr = 0;              /* pointer to input fid */
2841     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2842     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
2843     int     errorCode = 0;              /* return code for caller */
2844     int     fileCode =  0;              /* return code from vol package */
2845     Volume * volptr = 0;                /* pointer to the volume header */
2846     struct client * client;             /* pointer to client structure */
2847     afs_int32 rights, anyrights;                /* rights for this and any user */
2848     struct client *t_client;            /* tmp ptr to client data */
2849     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2850     struct rx_connection *tcon;
2851 #if FS_STATS_DETAILED
2852     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2853     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2854     struct timeval opStartTime,
2855                    opStopTime;              /* Start/stop times for RPC op*/
2856     struct timeval xferStartTime,
2857                    xferStopTime;            /* Start/stop times for xfer portion*/
2858     struct timeval elapsedTime;             /* Transfer time */
2859     afs_int32 bytesToXfer;                          /* # bytes to xfer */
2860     afs_int32 bytesXferred;                         /* # bytes actually xfer */
2861     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2862
2863     /*
2864      * Set our stats pointers, remember when the RPC operation started, and
2865      * tally the operation.
2866      */
2867     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2868     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2869     FS_LOCK
2870     (opP->numOps)++;
2871     FS_UNLOCK
2872
2873     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2874             Fid->Volume, Fid->Vnode, Fid->Unique));
2875     TM_GetTimeOfDay(&opStartTime, 0);
2876 #endif /* FS_STATS_DETAILED */
2877
2878     FS_LOCK
2879     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2880     FS_UNLOCK
2881
2882     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2883         goto Bad_StoreData;
2884
2885     /* Get ptr to client data for user Id for logging */
2886     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2887     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2888     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2889             Fid->Volume, Fid->Vnode, Fid->Unique,
2890             inet_ntoa(logHostAddr), t_client->ViceId));
2891
2892     /*
2893      * Get associated volume/vnode for the stored file; caller's rights
2894      * are also returned
2895      */
2896     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2897                                      MustNOTBeDIR, &parentwhentargetnotdir,
2898                                      &client, WRITE_LOCK, &rights, &anyrights))) {
2899         goto Bad_StoreData;
2900     }
2901
2902     /* set volume synchronization information */
2903     SetVolumeSync(Sync, volptr);
2904
2905     if ((targetptr->disk.type == vSymlink)) {
2906         /* Should we return a better error code here??? */
2907         errorCode = EISDIR;
2908         goto Bad_StoreData;
2909     }
2910
2911     /* Check if we're allowed to store the data */
2912     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2913                                            CHK_STOREDATA, InStatus))) {
2914         goto Bad_StoreData;
2915     }
2916
2917     /*
2918      * Drop the read lock on the parent directory after saving the parent
2919      * vnode information we need to pass to GetStatus
2920      */
2921     if (parentwhentargetnotdir != NULL) {
2922         tparentwhentargetnotdir = *parentwhentargetnotdir;
2923         VPutVnode(&fileCode, parentwhentargetnotdir);
2924         assert(!fileCode || (fileCode == VSALVAGE));
2925         parentwhentargetnotdir = NULL;
2926     }
2927
2928
2929
2930 #if FS_STATS_DETAILED
2931     /*
2932      * Remember when the data transfer started.
2933      */
2934     TM_GetTimeOfDay(&xferStartTime, 0);
2935 #endif /* FS_STATS_DETAILED */
2936
2937     /* Do the actual storing of the data */
2938 #if FS_STATS_DETAILED
2939     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2940                                   Pos, Length, FileLength,
2941                                   (InStatus->Mask & AFS_FSYNC),
2942                                   &bytesToXfer, &bytesXferred);
2943 #else
2944     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2945                                       acall, Pos, Length, FileLength,
2946                                       (InStatus->Mask & AFS_FSYNC));
2947     if (errorCode && (!targetptr->changed_newTime))
2948             goto Bad_StoreData;
2949 #endif /* FS_STATS_DETAILED */
2950 #if FS_STATS_DETAILED
2951     /*
2952      * At this point, the data transfer is done, for good or ill.  Remember
2953      * when the transfer ended, bump the number of successes/failures, and
2954      * integrate the transfer size and elapsed time into the stats.  If the
2955      * operation failed, we jump to the appropriate point.
2956      */
2957     TM_GetTimeOfDay(&xferStopTime, 0);
2958     FS_LOCK
2959     (xferP->numXfers)++;
2960     if (!errorCode) {
2961         (xferP->numSuccesses)++;
2962
2963         /*
2964          * Bump the xfer sum by the number of bytes actually sent, NOT the
2965          * target number.
2966          */
2967         tot_bytesXferred += bytesXferred;
2968         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2969         tot_bytesXferred &= 0x3FF;
2970         if (bytesXferred < xferP->minBytes)
2971             xferP->minBytes = bytesXferred;
2972         if (bytesXferred > xferP->maxBytes)
2973             xferP->maxBytes = bytesXferred;
2974       
2975         /*
2976          * Tally the size of the object.  Note: we tally the actual size,
2977          * NOT the number of bytes that made it out over the wire.
2978          */
2979         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2980             (xferP->count[0])++;
2981         else
2982             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2983                 (xferP->count[1])++;
2984         else
2985             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2986                 (xferP->count[2])++;
2987         else
2988             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2989                 (xferP->count[3])++;
2990         else
2991             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2992                 (xferP->count[4])++;
2993         else
2994             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2995                 (xferP->count[5])++;
2996         else
2997             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2998                 (xferP->count[6])++;
2999         else
3000             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3001                 (xferP->count[7])++;
3002         else
3003             (xferP->count[8])++;
3004       
3005         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3006         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3007         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3008         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3009             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3010         }
3011         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3012             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3013         }
3014     }
3015     FS_UNLOCK
3016
3017     /*
3018      * Finally, go off to tell our caller the bad news in case the
3019      * store failed.
3020      */
3021     if (errorCode && (!targetptr->changed_newTime))
3022             goto Bad_StoreData;
3023 #endif /* FS_STATS_DETAILED */
3024
3025     /* Update the status of the target's vnode */
3026     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
3027                              volptr, 0);
3028
3029     /* Get the updated File's status back to the caller */
3030     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
3031
3032 Bad_StoreData: 
3033     /* Update and store volume/vnode and parent vnodes back */
3034     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3035     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3036
3037     errorCode = CallPostamble(tcon, errorCode);
3038
3039 #if FS_STATS_DETAILED
3040     TM_GetTimeOfDay(&opStopTime, 0);
3041     if (errorCode == 0) {
3042         FS_LOCK
3043         (opP->numSuccesses)++;
3044         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3045         fs_stats_AddTo((opP->sumTime), elapsedTime);
3046         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3047         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3048             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3049         }
3050         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3051             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3052         }
3053         FS_UNLOCK
3054       }
3055 #endif /* FS_STATS_DETAILED */
3056
3057     osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
3058     return(errorCode);
3059
3060 } /*SRXAFS_StoreData*/
3061
3062 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,            
3063                               struct AFSFid *Fid,               
3064                               struct AFSStoreStatus *InStatus,  
3065                               afs_uint64 Pos,                   
3066                               afs_uint64 Length,                
3067                               afs_uint64 FileLength,            
3068                               struct AFSFetchStatus *OutStatus, 
3069                               struct AFSVolSync *Sync)
3070 {
3071     int code;
3072     afs_int32 tPos;
3073     afs_int32 tLength;
3074     afs_int32 tFileLength;
3075
3076 #ifdef AFS_64BIT_ENV
3077     if (FileLength > 0x7fffffff)
3078         return E2BIG;
3079     tPos = Pos;
3080     tLength = Length;
3081     tFileLength = FileLength;
3082 #else /* AFS_64BIT_ENV */
3083     if (FileLength.high)
3084         return E2BIG;
3085     tPos = Pos.low;
3086     tLength = Length.low;
3087     tFileLength = FileLength.low;
3088 #endif /* AFS_64BIT_ENV */
3089
3090     code = SRXAFS_StoreData (acall, Fid, InStatus, tPos, tLength, tFileLength,
3091                              OutStatus, Sync);
3092     return code;
3093 }
3094
3095 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,               
3096                            struct AFSFid *Fid,                  
3097                            struct AFSOpaque *AccessList,        
3098                            struct AFSFetchStatus *OutStatus,
3099                            struct AFSVolSync *Sync)
3100 {
3101     Vnode * targetptr = 0;              /* pointer to input fid */
3102     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3103     int     errorCode = 0;              /* return code for caller */
3104     struct AFSStoreStatus InStatus;     /* Input status for fid */
3105     Volume * volptr = 0;                /* pointer to the volume header */
3106     struct client * client;             /* pointer to client structure */
3107     afs_int32 rights, anyrights;                /* rights for this and any user */
3108     struct rx_connection *tcon;
3109     struct client *t_client;            /* tmp ptr to client data */
3110     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
3111 #if FS_STATS_DETAILED
3112     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3113     struct timeval opStartTime,
3114                    opStopTime;              /* Start/stop times for RPC op*/
3115     struct timeval elapsedTime;             /* Transfer time */
3116
3117     /*
3118      * Set our stats pointer, remember when the RPC operation started, and
3119      * tally the operation.
3120      */
3121     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3122     FS_LOCK
3123     (opP->numOps)++;
3124     FS_UNLOCK
3125     TM_GetTimeOfDay(&opStartTime, 0);
3126 #endif /* FS_STATS_DETAILED */
3127     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3128         goto Bad_StoreACL;
3129
3130     /* Get ptr to client data for user Id for logging */
3131     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3132     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3133     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3134             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3135             inet_ntoa(logHostAddr), t_client->ViceId));
3136     FS_LOCK
3137     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3138     FS_UNLOCK
3139
3140     InStatus.Mask = 0;      /* not storing any status */
3141
3142     /*
3143      * Get associated volume/vnode for the target dir; caller's rights
3144      * are also returned.
3145      */
3146     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3147                                      MustBeDIR, &parentwhentargetnotdir,
3148                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3149         goto Bad_StoreACL;
3150     }
3151
3152     /* set volume synchronization information */
3153     SetVolumeSync(Sync, volptr);
3154
3155     /* Check if we have permission to change the dir's ACL */
3156     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3157                                            CHK_STOREACL, &InStatus))) {
3158         goto Bad_StoreACL;
3159     }
3160
3161     /* Build and store the new Access List for the dir */
3162     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3163         goto Bad_StoreACL;
3164     }
3165     
3166     targetptr->changed_newTime = 1; /* status change of directory */
3167
3168     /* convert the write lock to a read lock before breaking callbacks */
3169     VVnodeWriteToRead(&errorCode, targetptr);
3170     assert(!errorCode || errorCode == VSALVAGE);
3171
3172     /* break call backs on the directory  */
3173     BreakCallBack(client->host, Fid, 0);
3174
3175     /* Get the updated dir's status back to the caller */
3176     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3177
3178 Bad_StoreACL: 
3179     /* Update and store volume/vnode and parent vnodes back */
3180     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3181     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
3182     errorCode = CallPostamble(tcon, errorCode);
3183
3184 #if FS_STATS_DETAILED
3185     TM_GetTimeOfDay(&opStopTime, 0);
3186     if (errorCode == 0) {
3187       FS_LOCK
3188       (opP->numSuccesses)++;
3189       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3190       fs_stats_AddTo((opP->sumTime), elapsedTime);
3191       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3192       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3193         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3194       }
3195       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3196         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3197       }
3198       FS_UNLOCK
3199     }
3200 #endif /* FS_STATS_DETAILED */
3201
3202     osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3203     return errorCode;
3204
3205 } /*SRXAFS_StoreACL*/
3206
3207
3208 /*
3209  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3210  * should be merged when possible.
3211  */
3212 static afs_int32
3213 SAFSS_StoreStatus (struct rx_call *acall,               
3214                    struct AFSFid *Fid,                  
3215                    struct AFSStoreStatus *InStatus,     
3216                    struct AFSFetchStatus *OutStatus,    
3217                    struct AFSVolSync *Sync)
3218
3219 {
3220     Vnode * targetptr = 0;              /* pointer to input fid */
3221     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3222     int     errorCode = 0;              /* return code for caller */
3223     Volume * volptr = 0;                /* pointer to the volume header */
3224     struct client * client;             /* pointer to client structure */
3225     afs_int32 rights, anyrights;                /* rights for this and any user */
3226     struct client *t_client;            /* tmp ptr to client data */
3227     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3228     struct rx_connection *tcon = rx_ConnectionOf(acall);
3229
3230     /* Get ptr to client data for user Id for logging */
3231     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3232     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3233     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
3234             Fid->Volume, Fid->Vnode,    Fid->Unique,
3235             inet_ntoa(logHostAddr), t_client->ViceId));
3236     FS_LOCK
3237     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3238     FS_UNLOCK
3239     /*
3240      * Get volume/vnode for the target file; caller's rights to it are
3241      * also returned
3242      */
3243     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3244                                      DONTCHECK, &parentwhentargetnotdir,
3245                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3246         goto Bad_StoreStatus;
3247     }
3248
3249     /* set volume synchronization information */
3250     SetVolumeSync(Sync, volptr);
3251
3252     /* Check if the caller has proper permissions to store status to Fid */
3253     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3254                                            CHK_STORESTATUS, InStatus))) {
3255         goto Bad_StoreStatus;
3256     }
3257     /*
3258      * Check for a symbolic link; we can't chmod these (otherwise could
3259      * change a symlink to a mt pt or vice versa)
3260      */
3261     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3262         errorCode = EINVAL;
3263         goto Bad_StoreStatus;
3264     }
3265
3266     /* Update the status of the target's vnode */
3267     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3268                              (parentwhentargetnotdir ?
3269                               parentwhentargetnotdir : targetptr), volptr, 0);
3270
3271     /* convert the write lock to a read lock before breaking callbacks */
3272     VVnodeWriteToRead(&errorCode, targetptr);
3273     assert(!errorCode || errorCode == VSALVAGE);
3274
3275     /* Break call backs on Fid */
3276     BreakCallBack(client->host, Fid, 0);
3277
3278     /* Return the updated status back to caller */
3279     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3280
3281 Bad_StoreStatus: 
3282     /* Update and store volume/vnode and parent vnodes back */
3283     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3284     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3285     return errorCode;
3286
3287 } /*SAFSS_StoreStatus*/
3288
3289
3290 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,            
3291                               struct AFSFid *Fid,               
3292                               struct AFSStoreStatus *InStatus,  
3293                               struct AFSFetchStatus *OutStatus, 
3294                               struct AFSVolSync *Sync)
3295 {
3296     afs_int32 code;
3297     struct rx_connection *tcon;
3298 #if FS_STATS_DETAILED
3299     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3300     struct timeval opStartTime,
3301                    opStopTime;              /* Start/stop times for RPC op*/
3302     struct timeval elapsedTime;             /* Transfer time */
3303
3304     /*
3305      * Set our stats pointer, remember when the RPC operation started, and
3306      * tally the operation.
3307      */
3308     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3309     FS_LOCK
3310     (opP->numOps)++;
3311     FS_UNLOCK
3312     TM_GetTimeOfDay(&opStartTime, 0);
3313 #endif /* FS_STATS_DETAILED */
3314
3315     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3316         goto Bad_StoreStatus;
3317
3318     code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3319
3320 Bad_StoreStatus:
3321     code = CallPostamble(tcon, code);
3322
3323 #if FS_STATS_DETAILED
3324     TM_GetTimeOfDay(&opStopTime, 0);
3325     if (code == 0) {
3326       FS_LOCK
3327       (opP->numSuccesses)++;
3328       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3329       fs_stats_AddTo((opP->sumTime), elapsedTime);
3330       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3331       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3332         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3333       }
3334       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3335         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3336       }
3337       FS_UNLOCK
3338     }
3339
3340 #endif /* FS_STATS_DETAILED */
3341
3342     osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3343     return code;
3344
3345 } /*SRXAFS_StoreStatus*/
3346
3347
3348 /*
3349  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3350  * merged in when possible.
3351  */
3352 static afs_int32
3353 SAFSS_RemoveFile (struct rx_call *acall,               
3354                   struct AFSFid *DirFid,               
3355                   char *Name,                          
3356                   struct AFSFetchStatus *OutDirStatus, 
3357                   struct AFSVolSync *Sync)
3358 {
3359     Vnode * parentptr = 0;              /* vnode of input Directory */
3360     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3361     Vnode * targetptr = 0;              /* file to be deleted */
3362     Volume * volptr = 0;                /* pointer to the volume header */
3363     AFSFid fileFid;                     /* area for Fid from the directory */
3364     int     errorCode = 0;              /* error code */
3365     DirHandle dir;                      /* Handle for dir package I/O */
3366     struct client * client;             /* pointer to client structure */
3367     afs_int32 rights, anyrights;                /* rights for this and any user */
3368     struct client *t_client;            /* tmp ptr to client data */
3369     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3370     struct rx_connection *tcon = rx_ConnectionOf(acall);
3371
3372     FidZero(&dir);
3373     /* Get ptr to client data for user Id for logging */
3374     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3375     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3376     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3377             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3378             inet_ntoa(logHostAddr), t_client->ViceId));
3379     FS_LOCK
3380     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3381     FS_UNLOCK
3382     /*
3383      * Get volume/vnode for the parent dir; caller's access rights are
3384      * also returned
3385      */
3386     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3387                                      MustBeDIR, &parentwhentargetnotdir,
3388                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3389         goto Bad_RemoveFile;
3390     }
3391     /* set volume synchronization information */
3392     SetVolumeSync(Sync, volptr);
3393
3394     /* Does the caller has delete (& write) access to the parent directory? */
3395     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3396         goto Bad_RemoveFile;
3397     }
3398
3399     /* Actually delete the desired file */
3400     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3401                                  &fileFid, Name, MustNOTBeDIR))) {
3402         goto Bad_RemoveFile;
3403     }
3404
3405     /* Update the vnode status of the parent dir */
3406 #if FS_STATS_DETAILED
3407     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3408                              parentptr->disk.linkCount, client->InSameNetwork);
3409 #else
3410     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3411                              parentptr->disk.linkCount);
3412 #endif /* FS_STATS_DETAILED */
3413
3414     /* Return the updated parent dir's status back to caller */
3415     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3416
3417     /* Handle internal callback state for the parent and the deleted file */
3418     if (targetptr->disk.linkCount == 0) {
3419         /* no references left, discard entry */
3420         DeleteFileCallBacks(&fileFid);
3421         /* convert the parent lock to a read lock before breaking callbacks */
3422         VVnodeWriteToRead(&errorCode, parentptr);
3423         assert(!errorCode || errorCode == VSALVAGE);
3424     } else {
3425         /* convert the parent lock to a read lock before breaking callbacks */
3426         VVnodeWriteToRead(&errorCode, parentptr);
3427         assert(!errorCode || errorCode == VSALVAGE);
3428         /* convert the target lock to a read lock before breaking callbacks */
3429         VVnodeWriteToRead(&errorCode, targetptr);
3430         assert(!errorCode || errorCode == VSALVAGE);
3431         /* tell all the file has changed */
3432         BreakCallBack(client->host, &fileFid, 1);
3433     }
3434
3435     /* break call back on the directory */
3436     BreakCallBack(client->host, DirFid, 0);
3437
3438 Bad_RemoveFile: 
3439     /* Update and store volume/vnode and parent vnodes back */
3440     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3441     FidZap(&dir);
3442     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
3443     return errorCode;
3444
3445 } /*SAFSS_RemoveFile*/
3446
3447
3448 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3449                              struct AFSFid *DirFid,
3450                              char *Name,
3451                              struct AFSFetchStatus *OutDirStatus,
3452                              struct AFSVolSync *Sync)
3453 {
3454     afs_int32 code;
3455     struct rx_connection *tcon;
3456 #if FS_STATS_DETAILED
3457     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3458     struct timeval opStartTime,
3459                    opStopTime;              /* Start/stop times for RPC op*/
3460     struct timeval elapsedTime;             /* Transfer time */
3461
3462     /*
3463      * Set our stats pointer, remember when the RPC operation started, and
3464      * tally the operation.
3465      */
3466     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3467     FS_LOCK
3468     (opP->numOps)++;
3469     FS_UNLOCK
3470     TM_GetTimeOfDay(&opStartTime, 0);
3471 #endif /* FS_STATS_DETAILED */
3472
3473     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3474         goto Bad_RemoveFile;
3475
3476     code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3477
3478 Bad_RemoveFile:    
3479     code = CallPostamble(tcon, code);
3480
3481 #if FS_STATS_DETAILED
3482     TM_GetTimeOfDay(&opStopTime, 0);
3483     if (code == 0) {
3484       FS_LOCK
3485       (opP->numSuccesses)++;
3486       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3487       fs_stats_AddTo((opP->sumTime), elapsedTime);
3488       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3489       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3490         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3491       }
3492       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3493         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3494       }
3495       FS_UNLOCK
3496     }
3497
3498 #endif /* FS_STATS_DETAILED */
3499
3500     osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3501     return code;
3502
3503 } /*SRXAFS_RemoveFile*/
3504
3505
3506 /*
3507  * This routine is called exclusively from SRXAFS_CreateFile(), and should
3508  * be merged in when possible.
3509  */
3510 static afs_int32
3511 SAFSS_CreateFile (struct rx_call *acall,
3512                   struct AFSFid *DirFid,
3513                   char *Name,
3514                   struct AFSStoreStatus *InStatus,
3515                   struct AFSFid *OutFid,
3516                   struct AFSFetchStatus *OutFidStatus,
3517                   struct AFSFetchStatus *OutDirStatus,
3518                   struct AFSCallBack *CallBack,
3519                   struct AFSVolSync *Sync)
3520 {
3521     Vnode * parentptr = 0;              /* vnode of input Directory */
3522     Vnode * targetptr = 0;              /* vnode of the new file */
3523     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3524     Volume * volptr = 0;                /* pointer to the volume header */
3525     int     errorCode = 0;              /* error code */
3526     DirHandle dir;                      /* Handle for dir package I/O */
3527     struct client * client;             /* pointer to client structure */
3528     afs_int32 rights, anyrights;                /* rights for this and any user */
3529     struct client *t_client;            /* tmp ptr to client data */
3530     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3531     struct rx_connection *tcon = rx_ConnectionOf(acall);
3532
3533     FidZero(&dir);
3534
3535     /* Get ptr to client data for user Id for logging */
3536     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3537     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3538     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3539             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3540             inet_ntoa(logHostAddr), t_client->ViceId));
3541     FS_LOCK
3542     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3543     FS_UNLOCK
3544     if (!FileNameOK(Name)) {
3545       errorCode = EINVAL;
3546       goto Bad_CreateFile;
3547     }
3548
3549     /*
3550      * Get associated volume/vnode for the parent dir; caller long are
3551      * also returned
3552      */
3553     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3554                                      MustBeDIR, &parentwhentargetnotdir,
3555                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3556         goto Bad_CreateFile;
3557     }
3558
3559     /* set volume synchronization information */
3560     SetVolumeSync(Sync, volptr);
3561
3562     /* Can we write (and insert) onto the parent directory? */
3563     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3564         goto Bad_CreateFile;
3565     }
3566     /* get a new vnode for the file to be created and set it up */
3567     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3568                                    Name, OutFid, vFile, nBlocks(0)))) {
3569         goto Bad_CreateFile;
3570     }
3571
3572     /* update the status of the parent vnode */
3573 #if FS_STATS_DETAILED
3574     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3575                              parentptr->disk.linkCount, client->InSameNetwork);
3576 #else
3577     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3578                              parentptr->disk.linkCount);
3579 #endif /* FS_STATS_DETAILED */
3580
3581     /* update the status of the new file's vnode */
3582     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3583                              parentptr, volptr, 0);
3584
3585     /* set up the return status for the parent dir and the newly created file */
3586     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3587     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3588
3589     /* convert the write lock to a read lock before breaking callbacks */
3590     VVnodeWriteToRead(&errorCode, parentptr);
3591     assert(!errorCode || errorCode == VSALVAGE);
3592     
3593     /* break call back on parent dir */
3594     BreakCallBack(client->host, DirFid, 0);
3595
3596     /* Return a callback promise for the newly created file to the caller */
3597     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3598
3599 Bad_CreateFile:
3600     /* Update and store volume/vnode and parent vnodes back */
3601     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3602     FidZap(&dir);
3603     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
3604     return errorCode;
3605
3606 } /*SAFSS_CreateFile*/
3607
3608
3609 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3610                              struct AFSFid *DirFid,
3611                              char *Name,
3612                              struct AFSStoreStatus *InStatus,
3613                              struct AFSFid *OutFid,
3614                              struct AFSFetchStatus *OutFidStatus,
3615                              struct AFSFetchStatus *OutDirStatus, 
3616                              struct AFSCallBack *CallBack,       
3617                              struct AFSVolSync *Sync)
3618 {
3619     afs_int32 code;
3620     struct rx_connection *tcon;
3621 #if FS_STATS_DETAILED
3622     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3623     struct timeval opStartTime,
3624                    opStopTime;              /* Start/stop times for RPC op*/
3625     struct timeval elapsedTime;             /* Transfer time */
3626
3627     /*
3628      * Set our stats pointer, remember when the RPC operation started, and
3629      * tally the operation.
3630      */
3631     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3632     FS_LOCK
3633     (opP->numOps)++;
3634     FS_UNLOCK
3635     TM_GetTimeOfDay(&opStartTime, 0);
3636 #endif /* FS_STATS_DETAILED */
3637
3638     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3639         goto Bad_CreateFile;
3640
3641     code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3642                             OutFidStatus, OutDirStatus, CallBack, Sync);
3643
3644 Bad_CreateFile:    
3645     code = CallPostamble(tcon, code);
3646
3647 #if FS_STATS_DETAILED
3648     TM_GetTimeOfDay(&opStopTime, 0);
3649     if (code == 0) {
3650       FS_LOCK
3651       (opP->numSuccesses)++;
3652       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3653       fs_stats_AddTo((opP->sumTime), elapsedTime);
3654       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3655       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3656         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3657       }
3658       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3659         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3660       }
3661       FS_UNLOCK
3662     }
3663 #endif /* FS_STATS_DETAILED */
3664
3665     osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3666     return code;
3667
3668 } /*SRXAFS_CreateFile*/
3669
3670
3671 /*
3672  * This routine is called exclusively from SRXAFS_Rename(), and should be
3673  * merged in when possible.
3674  */
3675 static afs_int32
3676 SAFSS_Rename (struct rx_call *acall,
3677               struct AFSFid *OldDirFid,
3678               char *OldName,
3679               struct AFSFid *NewDirFid,
3680               char *NewName,
3681               struct AFSFetchStatus *OutOldDirStatus,
3682               struct AFSFetchStatus *OutNewDirStatus,
3683               struct AFSVolSync *Sync)
3684 {
3685     Vnode * oldvptr = 0;        /* vnode of the old Directory */
3686     Vnode * newvptr = 0;        /* vnode of the new Directory */
3687     Vnode * fileptr = 0;        /* vnode of the file to move */
3688     Vnode * newfileptr = 0;     /* vnode of the file to delete */
3689     Vnode * testvptr = 0;       /* used in directory tree walk */
3690     Vnode * parent = 0;         /* parent for use in SetAccessList */
3691     int     errorCode = 0;      /* error code */
3692     int     fileCode = 0;       /* used when writing Vnodes */
3693     VnodeId testnode;           /* used in directory tree walk */
3694     AFSFid fileFid;             /* Fid of file to move */
3695     AFSFid newFileFid;          /* Fid of new file */
3696     DirHandle olddir;           /* Handle for dir package I/O */
3697     DirHandle newdir;           /* Handle for dir package I/O */
3698     DirHandle filedir;          /* Handle for dir package I/O */
3699     DirHandle newfiledir;       /* Handle for dir package I/O */
3700     Volume * volptr = 0;        /* pointer to the volume header */
3701     struct client * client;     /* pointer to client structure */
3702     afs_int32 rights, anyrights;        /* rights for this and any user */
3703     afs_int32 newrights;                /* rights for this user */
3704     afs_int32 newanyrights;             /* rights for any user */
3705     int doDelete;               /* deleted the rename target (ref count now 0) */
3706     int code;
3707     struct client *t_client;            /* tmp ptr to client data */
3708     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3709     struct rx_connection *tcon = rx_ConnectionOf(acall);
3710
3711     FidZero(&olddir);
3712     FidZero(&newdir);
3713     FidZero(&filedir);
3714     FidZero(&newfiledir);
3715
3716     /* Get ptr to client data for user Id for logging */
3717     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3718     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3719     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3720             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3721             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3722             NewDirFid->Unique,
3723             inet_ntoa(logHostAddr), t_client->ViceId));
3724     FS_LOCK
3725     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3726     FS_UNLOCK
3727     if (!FileNameOK(NewName)) {
3728         errorCode = EINVAL;
3729         goto Bad_Rename;
3730     }
3731     if (OldDirFid->Volume != NewDirFid->Volume) {
3732         DFlush();
3733         errorCode = EXDEV;
3734         goto Bad_Rename;
3735     }
3736     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3737          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
3738          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
3739         DFlush();
3740         errorCode = EINVAL;
3741         goto Bad_Rename;
3742     }
3743
3744     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3745         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3746                                           &oldvptr, MustBeDIR, &parent,
3747                                           &client, WRITE_LOCK, &rights,
3748                                           &anyrights)) {
3749             DFlush();
3750             goto Bad_Rename;
3751         }
3752         if (OldDirFid->Vnode == NewDirFid->Vnode) {
3753             newvptr = oldvptr;
3754             newrights = rights, newanyrights = anyrights;
3755         }
3756         else
3757             if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3758                                              &newvptr, MustBeDIR, &parent,
3759                                              &client, WRITE_LOCK, &newrights,
3760                                              &newanyrights))) {
3761                 DFlush();
3762                 goto Bad_Rename;
3763             }
3764     }
3765     else {
3766         if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3767                                          &newvptr, MustBeDIR, &parent,
3768                                          &client, WRITE_LOCK, &newrights,
3769                                          &newanyrights))) {
3770             DFlush();
3771             goto Bad_Rename;
3772         }
3773         if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3774                                          MustBeDIR, &parent, &client, WRITE_LOCK,
3775                                          &rights, &anyrights))) {
3776             DFlush();
3777             goto Bad_Rename;
3778         }
3779     }
3780
3781     /* set volume synchronization information */
3782     SetVolumeSync(Sync, volptr);
3783
3784     if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3785         goto Bad_Rename;
3786     }
3787     if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3788         goto Bad_Rename;
3789     }
3790
3791     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3792     *  call to CopyOnWrite returns error, it is not necessary to revert back
3793     *  the effects of the first call because the contents of the volume is 
3794     *  not modified, it is only replicated.
3795     */
3796     if (oldvptr->disk.cloned)
3797     {
3798         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
3799          if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3800                 goto Bad_Rename;
3801     }
3802     SetDirHandle(&olddir, oldvptr);
3803     if (newvptr->disk.cloned)
3804     {
3805         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
3806         if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3807                 goto Bad_Rename;        
3808     }
3809
3810     SetDirHandle(&newdir, newvptr);
3811
3812     /* Lookup the file to delete its vnode */
3813     if (Lookup(&olddir, OldName, &fileFid)) {
3814         errorCode = ENOENT;
3815         goto Bad_Rename;
3816     }
3817     if (fileFid.Vnode == oldvptr->vnodeNumber ||
3818         fileFid.Vnode == newvptr->vnodeNumber) {
3819         errorCode = FSERR_ELOOP;
3820         goto Bad_Rename;
3821     }
3822     fileFid.Volume = V_id(volptr);
3823     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3824     if (errorCode != 0) {
3825         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3826         VTakeOffline (volptr);
3827         goto Bad_Rename;
3828     }
3829     if (fileptr->disk.uniquifier != fileFid.Unique) {
3830         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3831         VTakeOffline (volptr);
3832         errorCode = EIO;
3833         goto Bad_Rename;
3834     }
3835
3836     if (fileptr->disk.type != vDirectory &&
3837         oldvptr != newvptr &&
3838         fileptr->disk.linkCount != 1) {
3839         /*
3840          * Hard links exist to this file - cannot move one of the links to
3841          * a new directory because of AFS restrictions (this is the same
3842          * reason that links cannot be made across directories, i.e.
3843          * access lists)
3844          */
3845         errorCode = EXDEV;
3846         goto Bad_Rename;
3847     }
3848
3849     /* Lookup the new file  */
3850     if (!(Lookup(&newdir, NewName, &newFileFid))) {
3851         if (readonlyServer) {
3852             errorCode = VREADONLY;
3853             goto Bad_Rename;
3854         }
3855         if (!(newrights & PRSFS_DELETE)) {
3856             errorCode = EACCES;
3857             goto Bad_Rename;
3858         }
3859         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3860                 newFileFid.Vnode == newvptr->vnodeNumber ||
3861                 newFileFid.Vnode == fileFid.Vnode) {
3862             errorCode = EINVAL;
3863             goto Bad_Rename;
3864         }
3865         newFileFid.Volume = V_id(volptr);
3866         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3867         if (errorCode != 0) {
3868             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3869             VTakeOffline (volptr);
3870             goto Bad_Rename;
3871         }
3872         if (fileptr->disk.uniquifier != fileFid.Unique) {
3873             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3874             VTakeOffline (volptr);
3875             errorCode = EIO;
3876             goto Bad_Rename;
3877         }
3878         SetDirHandle(&newfiledir, newfileptr);
3879         /* Now check that we're moving directories over directories properly, etc.
3880          * return proper POSIX error codes:
3881          * if fileptr is a file and new is a dir: EISDIR.
3882          * if fileptr is a dir and new is a file: ENOTDIR.
3883          * Also, dir to be removed must be empty, of course.
3884          */
3885         if (newfileptr->disk.type == vDirectory) {
3886             if (fileptr->disk.type != vDirectory) {
3887                 errorCode = EISDIR;
3888                 goto Bad_Rename;
3889             }
3890             if ((IsEmpty(&newfiledir))) {
3891                 errorCode = EEXIST;
3892                 goto Bad_Rename;
3893             }
3894         }
3895         else {
3896             if (fileptr->disk.type == vDirectory) {
3897                 errorCode = ENOTDIR;
3898                 goto Bad_Rename;
3899             }
3900         }
3901     }
3902
3903     /*
3904      * ok - now we check that the old name is not above new name in the
3905      * directory structure.  This is to prevent removing a subtree alltogether
3906      */
3907     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3908         for (testnode = newvptr->disk.parent; testnode != 0;) {
3909             if (testnode == oldvptr->vnodeNumber) {
3910                 testnode = oldvptr->disk.parent;
3911                 continue;
3912             }
3913             if ((testnode == fileptr->vnodeNumber) ||
3914                 (testnode == newvptr->vnodeNumber)) {
3915                 errorCode = FSERR_ELOOP;
3916                 goto Bad_Rename;
3917             }
3918             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3919                 errorCode = FSERR_ELOOP;
3920                 goto Bad_Rename;
3921             }
3922             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3923             assert(errorCode == 0);
3924             testnode = testvptr->disk.parent;
3925             VPutVnode(&errorCode, testvptr);
3926             assert(errorCode == 0);
3927         }
3928     }
3929     /* Do the CopyonWrite first before modifying anything else. Copying is
3930      *  required because we may have to change entries for .. 
3931      */
3932     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3933     {
3934         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
3935         if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3936                 goto Bad_Rename;
3937     }
3938
3939     /* If the new name exists already, delete it and the file it points to */
3940     doDelete = 0;
3941     if (newfileptr) {
3942         /* Delete NewName from its directory */
3943         code = Delete(&newdir, NewName);
3944         assert(code == 0);
3945
3946         /* Drop the link count */
3947         newfileptr->disk.linkCount--;
3948         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
3949             VAdjustDiskUsage(&errorCode, volptr,
3950                              -(int)nBlocks(newfileptr->disk.length), 0);
3951             if (VN_GET_INO(newfileptr)) {
3952                 IH_REALLYCLOSE(newfileptr->handle);
3953                 errorCode = IH_DEC(V_linkHandle(volptr),
3954                                  VN_GET_INO(newfileptr),
3955                                  V_parentId(volptr));
3956                 IH_RELEASE(newfileptr->handle);
3957                 if (errorCode == -1) {
3958                     ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
3959                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
3960                                 NewName, errno));
3961                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
3962                         ViceLog(0, ("Do we need to fsck?"));
3963                 } 
3964             }
3965             VN_SET_INO(newfileptr, (Inode)0);
3966             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
3967             doDelete = 1;
3968         } else {
3969             /* Link count did not drop to zero.
3970              * Mark NewName vnode as changed - updates stime.
3971              */
3972             newfileptr->changed_newTime = 1;
3973         }
3974     }
3975     
3976     /*
3977      * If the create below fails, and the delete above worked, we have
3978      * removed the new name and not replaced it.  This is not very likely,
3979      * but possible.  We could try to put the old file back, but it is
3980      * highly unlikely that it would work since it would involve issuing
3981      * another create.
3982      */
3983     if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
3984         goto Bad_Rename;
3985
3986     /* Delete the old name */
3987     assert(Delete(&olddir,(char *) OldName) == 0);
3988
3989     /* if the directory length changes, reflect it in the statistics */
3990 #if FS_STATS_DETAILED
3991     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
3992                              oldvptr->disk.linkCount, client->InSameNetwork);
3993     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
3994                              newvptr->disk.linkCount, client->InSameNetwork);
3995 #else
3996     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
3997                              oldvptr->disk.linkCount);
3998     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
3999                              newvptr->disk.linkCount);
4000 #endif /* FS_STATS_DETAILED */
4001
4002     if (oldvptr == newvptr)
4003         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
4004
4005     fileptr->disk.parent = newvptr->vnodeNumber;
4006     fileptr->changed_newTime = 1;       /* status change of moved file */
4007
4008     /* if we are dealing with a rename of a directory */
4009     if (fileptr->disk.type == vDirectory) {
4010         assert(!fileptr->disk.cloned);          
4011         SetDirHandle(&filedir, fileptr);
4012         /* fix .. to point to the correct place */
4013         Delete(&filedir, ".."); /* No assert--some directories may be bad */
4014         assert(Create(&filedir, "..", NewDirFid) == 0);
4015         fileptr->disk.dataVersion++;
4016         /* if the parent directories are different the link counts have to be   */
4017         /* changed due to .. in the renamed directory */
4018         if (oldvptr != newvptr) {
4019             oldvptr->disk.linkCount--;
4020             newvptr->disk.linkCount++;
4021         }
4022     }
4023
4024     /* set up return status */
4025     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
4026     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
4027     if (newfileptr && doDelete) {
4028         DeleteFileCallBacks(&newFileFid);       /* no other references */
4029     }
4030
4031     DFlush();
4032
4033     /* convert the write locks to a read locks before breaking callbacks */
4034     VVnodeWriteToRead(&errorCode, newvptr);
4035     assert(!errorCode || errorCode == VSALVAGE);
4036     if (oldvptr != newvptr) {
4037         VVnodeWriteToRead(&errorCode, oldvptr);
4038         assert(!errorCode || errorCode == VSALVAGE);
4039     }
4040     if (newfileptr && !doDelete) {
4041         /* convert the write lock to a read lock before breaking callbacks */
4042         VVnodeWriteToRead(&errorCode, newfileptr);
4043         assert(!errorCode || errorCode == VSALVAGE);
4044     }
4045
4046     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
4047     BreakCallBack(client->host, NewDirFid, 0);
4048     if (oldvptr != newvptr) {
4049         BreakCallBack(client->host, OldDirFid, 0);
4050         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
4051             BreakCallBack(client->host, &fileFid, 0);
4052     }
4053     if (newfileptr) {
4054         /* Note:  it is not necessary to break the callback */
4055         if (doDelete)
4056             DeleteFileCallBacks(&newFileFid);   /* no other references */
4057         else
4058             /* other's still exist (with wrong link count) */
4059             BreakCallBack(client->host, &newFileFid, 1);
4060     }
4061
4062 Bad_Rename: 
4063     if (newfileptr) {
4064         VPutVnode(&fileCode, newfileptr);
4065         assert(fileCode == 0);
4066     }
4067     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
4068                      oldvptr, volptr);
4069     FidZap(&olddir);
4070     FidZap(&newdir);
4071     FidZap(&filedir);
4072     FidZap(&newfiledir);
4073     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4074     return errorCode;
4075
4076 } /*SAFSS_Rename*/
4077
4078
4079 afs_int32 SRXAFS_Rename (struct rx_call *acall,              
4080                          struct AFSFid *OldDirFid,                   
4081                          char *OldName,                      
4082                          struct AFSFid *NewDirFid,
4083                          char *NewName,
4084                          struct AFSFetchStatus *OutOldDirStatus,
4085                          struct AFSFetchStatus *OutNewDirStatus,
4086                          struct AFSVolSync *Sync)
4087 {
4088     afs_int32 code;
4089     struct rx_connection *tcon;
4090 #if FS_STATS_DETAILED
4091     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4092     struct timeval opStartTime,
4093                    opStopTime;              /* Start/stop times for RPC op*/
4094     struct timeval elapsedTime;             /* Transfer time */
4095
4096     /*
4097      * Set our stats pointer, remember when the RPC operation started, and
4098      * tally the operation.
4099      */
4100     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4101     FS_LOCK
4102     (opP->numOps)++;
4103     FS_UNLOCK
4104     TM_GetTimeOfDay(&opStartTime, 0);
4105 #endif /* FS_STATS_DETAILED */
4106
4107     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4108         goto Bad_Rename;
4109
4110     code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4111                          OutOldDirStatus, OutNewDirStatus, Sync);
4112
4113 Bad_Rename:    
4114     code = CallPostamble(tcon, code);
4115
4116 #if FS_STATS_DETAILED
4117     TM_GetTimeOfDay(&opStopTime, 0);
4118     if (code == 0) {
4119       FS_LOCK
4120       (opP->numSuccesses)++;
4121       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4122       fs_stats_AddTo((opP->sumTime), elapsedTime);
4123       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4124       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4125         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4126       }
4127       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4128         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4129       }
4130       FS_UNLOCK
4131     }
4132
4133 #endif /* FS_STATS_DETAILED */
4134
4135     osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
4136     return code;
4137
4138 } /*SRXAFS_Rename*/
4139
4140
4141 /*
4142  * This routine is called exclusively by SRXAFS_Symlink(), and should be
4143  * merged into it when possible.
4144  */
4145 static afs_int32 
4146 SAFSS_Symlink (struct rx_call *acall,
4147                struct AFSFid *DirFid,
4148                char *Name,
4149                char *LinkContents,
4150                struct AFSStoreStatus *InStatus,
4151                struct AFSFid *OutFid,
4152                struct AFSFetchStatus *OutFidStatus,
4153                struct AFSFetchStatus *OutDirStatus,
4154                struct AFSVolSync *Sync)         
4155
4156 {
4157     Vnode * parentptr = 0;              /* vnode of input Directory */
4158     Vnode * targetptr = 0;              /* vnode of the new link */
4159     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4160     int     errorCode = 0;              /* error code */
4161     int code = 0;
4162     DirHandle dir;                      /* Handle for dir package I/O */
4163     Volume * volptr = 0;                /* pointer to the volume header */
4164     struct client * client;             /* pointer to client structure */
4165     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
4166     struct client *t_client;            /* tmp ptr to client data */
4167     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4168     FdHandle_t *fdP;
4169     struct rx_connection *tcon = rx_ConnectionOf(acall);
4170
4171     FidZero(&dir);
4172
4173     /* Get ptr to client data for user Id for logging */
4174     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4175     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4176     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
4177             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4178             inet_ntoa(logHostAddr), t_client->ViceId));
4179     FS_LOCK
4180     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
4181     FS_UNLOCK
4182     if (!FileNameOK(Name)) {
4183         errorCode = EINVAL;
4184         goto Bad_SymLink;
4185     }
4186
4187     /*
4188      * Get the vnode and volume for the parent dir along with the caller's
4189      * rights to it
4190      */
4191     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4192                                      MustBeDIR, &parentwhentargetnotdir,
4193                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4194         goto Bad_SymLink;
4195     }
4196
4197     /* set volume synchronization information */
4198     SetVolumeSync(Sync, volptr);
4199
4200     /* Does the caller has insert (and write) access to the parent directory? */
4201     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4202         goto Bad_SymLink;
4203     }
4204
4205     /*
4206      * If we're creating a mount point (any x bits clear), we must have
4207      * administer access to the directory, too.  Always allow sysadmins
4208      * to do this.
4209      */
4210     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
4211         if (readonlyServer) {
4212             errorCode = VREADONLY;
4213             goto Bad_SymLink;
4214         }
4215         /*
4216          * We have a mountpoint, 'cause we're trying to set the Unix mode
4217          * bits to something with some x bits missing (default mode bits
4218          * if AFS_SETMODE is false is 0777)
4219          */
4220         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
4221             errorCode = EACCES;
4222             goto Bad_SymLink;
4223         }
4224     }
4225  
4226     /* get a new vnode for the symlink and set it up */
4227     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
4228                                    Name, OutFid, vSymlink,
4229                                    nBlocks(strlen((char *) LinkContents))))) {
4230         goto Bad_SymLink;
4231     }
4232
4233     /* update the status of the parent vnode */
4234 #if FS_STATS_DETAILED
4235     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4236                              parentptr->disk.linkCount, client->InSameNetwork);
4237 #else
4238     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4239                              parentptr->disk.linkCount);
4240 #endif /* FS_STATS_DETAILED */
4241
4242     /* update the status of the new symbolic link file vnode */
4243     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
4244                              volptr, strlen((char *)LinkContents));
4245
4246     /* Write the contents of the symbolic link name into the target inode */
4247     fdP = IH_OPEN(targetptr->handle);
4248     assert(fdP != NULL);
4249     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
4250     FDH_CLOSE(fdP);
4251     /*
4252      * Set up and return modified status for the parent dir and new symlink
4253      * to caller.
4254      */
4255     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4256     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4257
4258     /* convert the write lock to a read lock before breaking callbacks */
4259     VVnodeWriteToRead(&errorCode, parentptr);
4260     assert(!errorCode || errorCode == VSALVAGE);
4261
4262     /* break call back on the parent dir */
4263     BreakCallBack(client->host, DirFid, 0);
4264
4265 Bad_SymLink: 
4266     /* Write the all modified vnodes (parent, new files) and volume back */
4267     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4268     FidZap(&dir);
4269     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
4270     return errorCode;
4271
4272 } /*SAFSS_Symlink*/
4273
4274
4275 afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
4276     struct AFSVolSync *Sync;
4277     struct rx_call *acall;               /* Rx call */
4278     struct AFSFid *DirFid;               /* Parent dir's fid */
4279     char *Name;                          /* File name to create */
4280     char *LinkContents;                  /* Contents of the new created file */
4281     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
4282     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
4283     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
4284     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
4285
4286 {
4287     afs_int32 code;
4288     struct rx_connection *tcon;
4289 #if FS_STATS_DETAILED
4290     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4291     struct timeval opStartTime,
4292                    opStopTime;              /* Start/stop times for RPC op*/
4293     struct timeval elapsedTime;             /* Transfer time */
4294
4295     /*
4296      * Set our stats pointer, remember when the RPC operation started, and
4297      * tally the operation.
4298      */
4299     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
4300     FS_LOCK
4301     (opP->numOps)++;
4302     FS_UNLOCK
4303     TM_GetTimeOfDay(&opStartTime, 0);
4304 #endif /* FS_STATS_DETAILED */
4305
4306     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4307         goto Bad_Symlink;
4308
4309     code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
4310                          OutFidStatus, OutDirStatus, Sync);
4311
4312 Bad_Symlink:    
4313     code = CallPostamble(tcon, code);
4314
4315 #if FS_STATS_DETAILED
4316     TM_GetTimeOfDay(&opStopTime, 0);
4317     if (code == 0) {
4318       FS_LOCK
4319       (opP->numSuccesses)++;
4320       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4321       fs_stats_AddTo((opP->sumTime), elapsedTime);
4322       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4323       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4324         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4325       }
4326       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4327         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4328       }
4329       FS_UNLOCK
4330     }
4331
4332 #endif /* FS_STATS_DETAILED */
4333
4334     osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4335     return code;
4336
4337 } /*SRXAFS_Symlink*/
4338
4339
4340 /*
4341  * This routine is called exclusively by SRXAFS_Link(), and should be
4342  * merged into it when possible.
4343  */
4344 static afs_int32 
4345 SAFSS_Link (struct rx_call *acall,
4346             struct AFSFid *DirFid,
4347             char *Name,
4348             struct AFSFid *ExistingFid,
4349             struct AFSFetchStatus *OutFidStatus,
4350             struct AFSFetchStatus *OutDirStatus,
4351             struct AFSVolSync *Sync)
4352 {
4353     Vnode * parentptr = 0;              /* vnode of input Directory */
4354     Vnode * targetptr = 0;              /* vnode of the new file */
4355     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4356     Volume * volptr = 0;                /* pointer to the volume header */
4357     int     errorCode = 0;              /* error code */
4358     DirHandle dir;                      /* Handle for dir package I/O */
4359     struct client * client;             /* pointer to client structure */
4360     afs_int32 rights, anyrights;                /* rights for this and any user */
4361     struct client *t_client;            /* tmp ptr to client data */
4362     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4363     struct rx_connection *tcon = rx_ConnectionOf(acall);
4364
4365     FidZero(&dir);
4366
4367     /* Get ptr to client data for user Id for logging */
4368     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4369     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4370     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
4371             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4372             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
4373             inet_ntoa(logHostAddr), t_client->ViceId));
4374     FS_LOCK
4375     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
4376     FS_UNLOCK
4377     if (DirFid->Volume != ExistingFid->Volume) {
4378         errorCode = EXDEV;
4379         goto Bad_Link;
4380     }
4381     if (!FileNameOK(Name)) {
4382         errorCode = EINVAL;
4383         goto Bad_Link;
4384     }
4385
4386     /*
4387      * Get the vnode and volume for the parent dir along with the caller's
4388      * rights to it
4389      */
4390     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4391                                      MustBeDIR, &parentwhentargetnotdir,
4392                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4393         goto Bad_Link;
4394     }
4395
4396     /* set volume synchronization information */
4397     SetVolumeSync(Sync, volptr);
4398
4399     /* Can the caller insert into the parent directory? */
4400     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4401         goto Bad_Link;
4402     }
4403
4404     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
4405         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
4406       /* AFS fileservers always have directory vnodes that are odd.   */
4407       errorCode = EISDIR;
4408       goto Bad_Link;
4409     }
4410
4411     /* get the file vnode  */
4412     if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
4413         goto Bad_Link;
4414     }
4415     if (targetptr->disk.type != vFile) {
4416         errorCode = EISDIR;
4417         goto Bad_Link;
4418     }
4419     if (targetptr->disk.parent != DirFid->Vnode) {
4420         errorCode = EXDEV;
4421         goto Bad_Link;
4422     }
4423     if (parentptr->disk.cloned) 
4424     {
4425         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
4426         if ( ( errorCode = CopyOnWrite(parentptr, volptr)))
4427                 goto Bad_Link;          /* disk full error */
4428     }
4429
4430     /* add the name to the directory */
4431     SetDirHandle(&dir, parentptr);
4432     if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
4433         goto Bad_Link;
4434     DFlush();
4435
4436     /* update the status in the parent vnode */
4437     /**WARNING** --> disk.author SHOULDN'T be modified???? */
4438 #if FS_STATS_DETAILED
4439     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4440                              parentptr->disk.linkCount, client->InSameNetwork);
4441 #else
4442     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4443                              parentptr->disk.linkCount);
4444 #endif /* FS_STATS_DETAILED */
4445
4446     targetptr->disk.linkCount++;
4447     targetptr->disk.author = client->ViceId;
4448     targetptr->changed_newTime = 1; /* Status change of linked-to file */
4449
4450     /* set up return status */
4451     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4452     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4453
4454     /* convert the write locks to read locks before breaking callbacks */
4455     VVnodeWriteToRead(&errorCode, targetptr);
4456     assert(!errorCode || errorCode == VSALVAGE);
4457     VVnodeWriteToRead(&errorCode, parentptr);
4458     assert(!errorCode || errorCode == VSALVAGE);
4459     
4460     /* break call back on DirFid */
4461     BreakCallBack(client->host, DirFid, 0);
4462     /*
4463      * We also need to break the callback for the file that is hard-linked since part 
4464      * of its status (like linkcount) is changed
4465      */
4466     BreakCallBack(client->host, ExistingFid, 0);
4467
4468 Bad_Link:
4469     /* Write the all modified vnodes (parent, new files) and volume back */
4470     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4471     FidZap(&dir);
4472     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
4473     return errorCode;
4474
4475 } /*SAFSS_Link*/
4476
4477
4478 afs_int32 SRXAFS_Link (struct rx_call *acall,
4479                        struct AFSFid *DirFid,
4480                        char *Name,
4481                        struct AFSFid *ExistingFid,
4482                        struct AFSFetchStatus *OutFidStatus,
4483                        struct AFSFetchStatus *OutDirStatus,
4484                        struct AFSVolSync *Sync)
4485 {
4486     afs_int32 code;
4487     struct rx_connection *tcon;
4488 #if FS_STATS_DETAILED
4489     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4490     struct timeval opStartTime,
4491                    opStopTime;              /* Start/stop times for RPC op*/
4492     struct timeval elapsedTime;             /* Transfer time */
4493
4494     /*
4495      * Set our stats pointer, remember when the RPC operation started, and
4496      * tally the operation.
4497      */
4498     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
4499     FS_LOCK
4500     (opP->numOps)++;
4501     FS_UNLOCK
4502     TM_GetTimeOfDay(&opStartTime, 0);
4503 #endif /* FS_STATS_DETAILED */
4504
4505     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4506         goto Bad_Link;
4507
4508     code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
4509                       OutDirStatus, Sync);
4510     
4511 Bad_Link:
4512     code = CallPostamble(tcon, code);
4513
4514 #if FS_STATS_DETAILED
4515     TM_GetTimeOfDay(&opStopTime, 0);
4516     if (code == 0) {
4517       FS_LOCK
4518       (opP->numSuccesses)++;
4519       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4520       fs_stats_AddTo((opP->sumTime), elapsedTime);
4521       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4522       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4523         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4524       }
4525       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4526         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4527       }
4528       FS_UNLOCK
4529     }
4530
4531 #endif /* FS_STATS_DETAILED */
4532
4533     osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
4534     return code;
4535
4536 } /*SRXAFS_Link*/
4537
4538
4539 /*
4540  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4541  * merged into it when possible.
4542  */
4543 static afs_int32
4544 SAFSS_MakeDir (struct rx_call *acall,
4545                struct AFSFid *DirFid,
4546                char *Name,
4547                struct AFSStoreStatus *InStatus,
4548                struct AFSFid *OutFid,
4549                struct AFSFetchStatus *OutFidStatus,
4550                struct AFSFetchStatus *OutDirStatus,
4551                struct AFSCallBack *CallBack,
4552                struct AFSVolSync *Sync)
4553
4554 {
4555     Vnode * parentptr = 0;              /* vnode of input Directory */
4556     Vnode * targetptr = 0;              /* vnode of the new file */
4557     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4558     Volume * volptr = 0;                /* pointer to the volume header */
4559     int     errorCode = 0;              /* error code */
4560     struct acl_accessList * newACL;     /* Access list */
4561     int     newACLSize;                 /* Size of access list */
4562     DirHandle dir;                      /* Handle for dir package I/O */
4563     DirHandle parentdir;                /* Handle for dir package I/O */
4564     struct client * client;             /* pointer to client structure */
4565     afs_int32 rights, anyrights;                /* rights for this and any user */
4566     struct client *t_client;            /* tmp ptr to client data */
4567     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4568     struct rx_connection *tcon = rx_ConnectionOf(acall);
4569
4570     FidZero(&dir);
4571     FidZero(&parentdir);
4572
4573     /* Get ptr to client data for user Id for logging */
4574     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4575     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4576     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4577             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4578             inet_ntoa(logHostAddr), t_client->ViceId));
4579     FS_LOCK
4580     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
4581     FS_UNLOCK
4582     if (!FileNameOK(Name)) {
4583         errorCode = EINVAL;
4584         goto Bad_MakeDir;
4585     }
4586
4587     /*
4588      * Get the vnode and volume for the parent dir along with the caller's
4589      * rights to it.
4590      */
4591     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4592                                      MustBeDIR, &parentwhentargetnotdir,
4593                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4594         goto Bad_MakeDir;
4595     }
4596  
4597     /* set volume synchronization information */
4598     SetVolumeSync(Sync, volptr);
4599
4600     /* Write access to the parent directory? */
4601 #ifdef DIRCREATE_NEED_WRITE
4602     /*
4603      * requires w access for the user to create a directory. this
4604      * closes a loophole in the current security arrangement, since a
4605      * user with i access only can create a directory and get the
4606      * implcit a access that goes with dir ownership, and proceed to 
4607      * subvert quota in the volume.
4608      */
4609     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
4610         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
4611 #else 
4612     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4613 #endif /* DIRCREATE_NEED_WRITE */ 
4614         goto Bad_MakeDir;
4615     }
4616
4617 #define EMPTYDIRBLOCKS 2
4618     /* get a new vnode and set it up */
4619     if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
4620                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) {
4621         goto Bad_MakeDir;
4622     }
4623
4624     /* Update the status for the parent dir */
4625 #if FS_STATS_DETAILED
4626     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4627                              parentptr->disk.linkCount+1, client->InSameNetwork);
4628 #else
4629     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4630                              parentptr->disk.linkCount+1);
4631 #endif /* FS_STATS_DETAILED */
4632
4633     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4634     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
4635                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
4636     assert(parentwhentargetnotdir == 0);
4637     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
4638
4639     /* update the status for the target vnode */
4640     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
4641                              parentptr, volptr, 0);
4642
4643     /* Actually create the New directory in the directory package */ 
4644     SetDirHandle(&dir, targetptr);
4645     assert(!(MakeDir(&dir, OutFid, DirFid)));
4646     DFlush();
4647     targetptr->disk.length = Length(&dir);
4648
4649     /* set up return status */
4650     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4651     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4652
4653     /* convert the write lock to a read lock before breaking callbacks */
4654     VVnodeWriteToRead(&errorCode, parentptr);
4655     assert(!errorCode || errorCode == VSALVAGE);
4656
4657     /* break call back on DirFid */
4658     BreakCallBack(client->host, DirFid, 0);
4659
4660     /* Return a callback promise to caller */
4661     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
4662
4663 Bad_MakeDir: 
4664     /* Write the all modified vnodes (parent, new files) and volume back */
4665     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4666     FidZap(&dir);
4667     FidZap(&parentdir);
4668     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
4669     return errorCode;
4670
4671 } /*SAFSS_MakeDir*/
4672
4673
4674 afs_int32 SRXAFS_MakeDir (struct rx_call *acall,
4675                           struct AFSFid *DirFid,
4676                           char *Name,
4677                           struct AFSStoreStatus *InStatus,
4678                           struct AFSFid *OutFid,
4679                           struct AFSFetchStatus *OutFidStatus,
4680                           struct AFSFetchStatus *OutDirStatus,
4681                           struct AFSCallBack *CallBack,
4682                           struct AFSVolSync *Sync)
4683 {
4684     afs_int32 code;
4685     struct rx_connection *tcon;
4686 #if FS_STATS_DETAILED
4687     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4688     struct timeval opStartTime,
4689                    opStopTime;              /* Start/stop times for RPC op*/
4690     struct timeval elapsedTime;             /* Transfer time */
4691
4692     /*
4693      * Set our stats pointer, remember when the RPC operation started, and
4694      * tally the operation.
4695      */
4696     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
4697     FS_LOCK
4698     (opP->numOps)++;
4699     FS_UNLOCK
4700     TM_GetTimeOfDay(&opStartTime, 0);
4701 #endif /* FS_STATS_DETAILED */
4702     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4703         goto Bad_MakeDir;
4704
4705     code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
4706                          OutFidStatus, OutDirStatus, CallBack, Sync);
4707     
4708 Bad_MakeDir:
4709     code = CallPostamble(tcon, code);
4710
4711 #if FS_STATS_DETAILED
4712     TM_GetTimeOfDay(&opStopTime, 0);
4713     if (code == 0) {
4714       FS_LOCK
4715       (opP->numSuccesses)++;
4716       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4717       fs_stats_AddTo((opP->sumTime), elapsedTime);
4718       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4719       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4720         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4721       }
4722       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4723         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4724       }
4725       FS_UNLOCK
4726     }
4727
4728 #endif /* FS_STATS_DETAILED */
4729
4730     osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4731     return code;
4732
4733 } /*SRXAFS_MakeDir*/
4734
4735
4736 /*
4737  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4738  * merged into it when possible.
4739  */
4740 static afs_int32
4741 SAFSS_RemoveDir (struct rx_call *acall,
4742                  struct AFSFid *DirFid,
4743                  char *Name,
4744                  struct AFSFetchStatus *OutDirStatus,
4745                  struct AFSVolSync *Sync)
4746
4747 {
4748     Vnode * parentptr = 0;              /* vnode of input Directory */
4749     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4750     Vnode * targetptr = 0;              /* file to be deleted */
4751     AFSFid fileFid;                     /* area for Fid from the directory */
4752     int     errorCode = 0;              /* error code */
4753     DirHandle dir;                      /* Handle for dir package I/O */
4754     Volume * volptr = 0;                /* pointer to the volume header */
4755     struct client * client;             /* pointer to client structure */
4756     afs_int32 rights, anyrights;                /* rights for this and any user */
4757     Vnode debugvnode1, debugvnode2;
4758     struct client *t_client;            /* tmp ptr to client data */
4759     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4760     struct rx_connection *tcon = rx_ConnectionOf(acall);
4761
4762     FidZero(&dir);
4763
4764     /* Get ptr to client data for user Id for logging */
4765     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4766     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4767     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4768             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4769             inet_ntoa(logHostAddr), t_client->ViceId));
4770     FS_LOCK
4771     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
4772     FS_UNLOCK
4773     /*
4774      * Get the vnode and volume for the parent dir along with the caller's
4775      * rights to it
4776      */
4777     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4778                                      MustBeDIR, &parentwhentargetnotdir,
4779                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4780         goto Bad_RemoveDir;
4781     }
4782     debugvnode1 = *parentptr;
4783
4784     /* set volume synchronization information */
4785     SetVolumeSync(Sync, volptr);
4786
4787     /* Does the caller has delete (&write) access to the parent dir? */
4788     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
4789         goto Bad_RemoveDir;
4790     }
4791
4792     debugvnode2 = *parentptr;
4793     /* Do the actual delete of the desired (empty) directory, Name */
4794     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
4795                                  Name, MustBeDIR))) {
4796         goto Bad_RemoveDir;
4797     }
4798
4799     /* Update the status for the parent dir; link count is also adjusted */
4800 #if FS_STATS_DETAILED
4801     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4802                              parentptr->disk.linkCount-1, client->InSameNetwork);
4803 #else
4804     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4805                              parentptr->disk.linkCount-1);
4806 #endif /* FS_STATS_DETAILED */
4807
4808     /* Return to the caller the updated parent dir status */
4809     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4810
4811     /*
4812      * Note: it is not necessary to break the callback on fileFid, since
4813      * refcount is now 0, so no one should be able to refer to the dir
4814      * any longer
4815      */
4816     DeleteFileCallBacks(&fileFid);
4817
4818     /* convert the write lock to a read lock before breaking callbacks */
4819     VVnodeWriteToRead(&errorCode, parentptr);
4820     assert(!errorCode || errorCode == VSALVAGE);
4821
4822     /* break call back on DirFid and fileFid */
4823     BreakCallBack(client->host, DirFid, 0);
4824
4825 Bad_RemoveDir: 
4826     /* Write the all modified vnodes (parent, new files) and volume back */
4827     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4828     FidZap(&dir);
4829     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
4830     return errorCode;
4831
4832 } /*SAFSS_RemoveDir*/
4833
4834
4835 afs_int32 SRXAFS_RemoveDir (struct rx_call *acall,
4836                             struct AFSFid *DirFid,
4837                             char *Name,
4838                             struct AFSFetchStatus *OutDirStatus,
4839                             struct AFSVolSync *Sync)
4840 {
4841     afs_int32 code;
4842     struct rx_connection *tcon;
4843 #if FS_STATS_DETAILED
4844     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4845     struct timeval opStartTime,
4846                    opStopTime;              /* Start/stop times for RPC op*/
4847     struct timeval elapsedTime;             /* Transfer time */
4848
4849     /*
4850      * Set our stats pointer, remember when the RPC operation started, and
4851      * tally the operation.
4852      */
4853     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
4854     FS_LOCK
4855     (opP->numOps)++;
4856     FS_UNLOCK
4857     TM_GetTimeOfDay(&opStartTime, 0);
4858 #endif /* FS_STATS_DETAILED */
4859
4860     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4861         goto Bad_RemoveDir;
4862
4863     code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
4864     
4865 Bad_RemoveDir:
4866     code = CallPostamble(tcon, code);
4867
4868 #if FS_STATS_DETAILED
4869     TM_GetTimeOfDay(&opStopTime, 0);
4870     if (code == 0) {
4871       FS_LOCK
4872       (opP->numSuccesses)++;
4873       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4874       fs_stats_AddTo((opP->sumTime), elapsedTime);
4875       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4876       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4877         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4878       }
4879       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4880         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4881       }
4882       FS_UNLOCK
4883     }
4884
4885 #endif /* FS_STATS_DETAILED */
4886
4887     osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4888     return code;
4889
4890 } /*SRXAFS_RemoveDir*/
4891
4892
4893 /*
4894  * This routine is called exclusively by SRXAFS_SetLock(), and should be
4895  * merged into it when possible.
4896  */
4897 static afs_int32
4898 SAFSS_SetLock (struct rx_call *acall,
4899                struct AFSFid *Fid,
4900                ViceLockType type,
4901                struct AFSVolSync *Sync)
4902 {
4903     Vnode * targetptr = 0;              /* vnode of input file */
4904     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4905     int     errorCode = 0;              /* error code */
4906     Volume * volptr = 0;                /* pointer to the volume header */
4907     struct client * client;             /* pointer to client structure */
4908     afs_int32 rights, anyrights;                /* rights for this and any user */
4909     struct client *t_client;            /* tmp ptr to client data */
4910     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4911     static char * locktype[2] = {"LockRead","LockWrite"};
4912     struct rx_connection *tcon = rx_ConnectionOf(acall);
4913
4914     if (type != LockRead && type != LockWrite) {
4915         errorCode = EINVAL;
4916         goto Bad_SetLock;
4917     }
4918     /* Get ptr to client data for user Id for logging */
4919     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4920     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4921     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
4922             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
4923             inet_ntoa(logHostAddr), t_client->ViceId));
4924     FS_LOCK
4925     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
4926     FS_UNLOCK
4927
4928     /*
4929      * Get the vnode and volume for the desired file along with the caller's
4930      * rights to it
4931      */
4932     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
4933                                      DONTCHECK, &parentwhentargetnotdir,
4934                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4935         goto Bad_SetLock;
4936     }
4937
4938     /* set volume synchronization information */
4939     SetVolumeSync(Sync, volptr);
4940
4941     /* Handle the particular type of set locking, type */
4942     errorCode = HandleLocking(targetptr, rights, type);
4943
4944 Bad_SetLock: 
4945     /* Write the all modified vnodes (parent, new files) and volume back */
4946     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
4947
4948     if ((errorCode == VREADONLY) && (type == LockRead))
4949        errorCode = 0;  /* allow read locks on RO volumes without saving state */
4950
4951     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
4952     return(errorCode);
4953
4954 }  /*SAFSS_SetLock*/
4955
4956
4957 afs_int32 SRXAFS_OldSetLock(struct rx_call *acall,
4958                             struct AFSFid *Fid,
4959                             ViceLockType type,
4960                             struct AFSVolSync *Sync)
4961 {
4962     return SRXAFS_SetLock(acall, Fid, type, Sync);
4963
4964 } /*SRXAFS_OldSetLock*/
4965
4966
4967 afs_int32 SRXAFS_SetLock (struct rx_call *acall,
4968                           struct AFSFid *Fid,
4969                           ViceLockType type,
4970                           struct AFSVolSync *Sync)
4971 {
4972     afs_int32 code;
4973     struct rx_connection *tcon;
4974 #if FS_STATS_DETAILED
4975     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4976     struct timeval opStartTime,
4977                    opStopTime;              /* Start/stop times for RPC op*/
4978     struct timeval elapsedTime;             /* Transfer time */
4979
4980     /*
4981      * Set our stats pointer, remember when the RPC operation started, and
4982      * tally the operation.
4983      */
4984     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
4985     FS_LOCK
4986     (opP->numOps)++;
4987     FS_UNLOCK
4988     TM_GetTimeOfDay(&opStartTime, 0);
4989 #endif /* FS_STATS_DETAILED */
4990
4991     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4992         goto Bad_SetLock;
4993
4994     code = SAFSS_SetLock (acall, Fid, type, Sync);
4995     
4996 Bad_SetLock:
4997     code = CallPostamble(tcon, code);
4998
4999 #if FS_STATS_DETAILED
5000     TM_GetTimeOfDay(&opStopTime, 0); 
5001     if (code == 0) {
5002       FS_LOCK
5003       (opP->numSuccesses)++;
5004       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5005       fs_stats_AddTo((opP->sumTime), elapsedTime);
5006       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5007       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5008         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5009       }
5010       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5011         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5012       }
5013       FS_UNLOCK
5014     }
5015 #endif /* FS_STATS_DETAILED */
5016
5017     osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
5018     return code;
5019
5020 } /*SRXAFS_SetLock*/
5021
5022
5023 /*
5024  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
5025  * merged into it when possible.
5026  */
5027 static afs_int32 
5028 SAFSS_ExtendLock (struct rx_call *acall,
5029                   struct AFSFid *Fid,
5030                   struct AFSVolSync *Sync)
5031
5032 {
5033     Vnode * targetptr = 0;              /* vnode of input file */
5034     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5035     int     errorCode = 0;              /* error code */
5036     Volume * volptr = 0;                /* pointer to the volume header */
5037     struct client * client;             /* pointer to client structure */
5038     afs_int32 rights, anyrights;                /* rights for this and any user */
5039     struct client *t_client;            /* tmp ptr to client data */
5040     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5041     struct rx_connection *tcon = rx_ConnectionOf(acall);
5042
5043     /* Get ptr to client data for user Id for logging */
5044     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5045     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5046     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
5047                Fid->Volume, Fid->Vnode, Fid->Unique, 
5048                inet_ntoa(logHostAddr), t_client->ViceId));
5049     FS_LOCK
5050     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
5051     FS_UNLOCK
5052     /*
5053      * Get the vnode and volume for the desired file along with the caller's
5054      * rights to it
5055      */
5056     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5057                                      DONTCHECK, &parentwhentargetnotdir,
5058                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5059         goto Bad_ExtendLock;
5060     }
5061
5062     /* set volume synchronization information */
5063     SetVolumeSync(Sync, volptr);
5064
5065     /* Handle the actual lock extension */
5066     errorCode = HandleLocking(targetptr, rights, LockExtend);
5067
5068 Bad_ExtendLock: 
5069     /* Put back file's vnode and volume */
5070     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5071
5072     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5073        errorCode = 0;              /* under our generous policy re RO vols */
5074
5075     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
5076     return(errorCode);
5077
5078 } /*SAFSS_ExtendLock*/
5079
5080
5081 afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall,
5082                                 struct AFSFid *Fid,
5083                                 struct AFSVolSync *Sync)
5084 {
5085     return SRXAFS_ExtendLock(acall, Fid, Sync);
5086
5087 } /*SRXAFS_OldExtendLock*/
5088
5089
5090 afs_int32 SRXAFS_ExtendLock (struct rx_call *acall,
5091                              struct AFSFid *Fid,
5092                              struct AFSVolSync *Sync)
5093 {
5094     afs_int32 code;
5095     struct rx_connection *tcon;
5096 #if FS_STATS_DETAILED
5097     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5098     struct timeval opStartTime,
5099                    opStopTime;              /* Start/stop times for RPC op*/
5100     struct timeval elapsedTime;             /* Transfer time */
5101
5102     /*
5103      * Set our stats pointer, remember when the RPC operation started, and
5104      * tally the operation.
5105      */
5106     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
5107     FS_LOCK
5108     (opP->numOps)++;
5109     FS_UNLOCK
5110     TM_GetTimeOfDay(&opStartTime, 0);
5111 #endif /* FS_STATS_DETAILED */
5112
5113     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5114         goto Bad_ExtendLock;
5115
5116     code = SAFSS_ExtendLock (acall, Fid, Sync);
5117
5118 Bad_ExtendLock:
5119     code = CallPostamble(tcon, code);
5120
5121 #if FS_STATS_DETAILED
5122     TM_GetTimeOfDay(&opStopTime, 0);
5123     if (code == 0) {
5124       FS_LOCK
5125       (opP->numSuccesses)++;
5126       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5127       fs_stats_AddTo((opP->sumTime), elapsedTime);
5128       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5129       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5130         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5131       }
5132       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5133         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5134       }
5135       FS_UNLOCK
5136     }
5137
5138 #endif /* FS_STATS_DETAILED */
5139
5140     osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
5141     return code;
5142
5143 } /*SRXAFS_ExtendLock*/
5144
5145
5146 /*
5147  * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
5148  * merged into it when possible.
5149  */
5150 static afs_int32 
5151 SAFSS_ReleaseLock (struct rx_call *acall,
5152                    struct AFSFid *Fid,
5153                    struct AFSVolSync *Sync)
5154
5155 {
5156     Vnode * targetptr = 0;              /* vnode of input file */
5157     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5158     int     errorCode = 0;              /* error code */
5159     Volume * volptr = 0;                /* pointer to the volume header */
5160     struct client * client;             /* pointer to client structure */
5161     afs_int32 rights, anyrights;                /* rights for this and any user */
5162     struct client *t_client;            /* tmp ptr to client data */
5163     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5164     struct rx_connection *tcon = rx_ConnectionOf(acall);
5165
5166     /* Get ptr to client data for user Id for logging */
5167     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5168     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5169     ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
5170             Fid->Volume, Fid->Vnode, Fid->Unique,
5171             inet_ntoa(logHostAddr), t_client->ViceId));
5172     FS_LOCK
5173     AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
5174     FS_UNLOCK
5175     /*
5176      * Get the vnode and volume for the desired file along with the caller's
5177      * rights to it
5178      */
5179     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5180                                      DONTCHECK, &parentwhentargetnotdir,
5181                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5182         goto Bad_ReleaseLock;
5183     }
5184
5185     /* set volume synchronization information */
5186     SetVolumeSync(Sync, volptr);
5187
5188     /* Handle the actual lock release */
5189     if ((errorCode = HandleLocking(targetptr, rights, LockRelease)))
5190         goto Bad_ReleaseLock;
5191
5192     /* if no more locks left, a callback would be triggered here */
5193     if (targetptr->disk.lock.lockCount <= 0) {
5194         /* convert the write lock to a read lock before breaking callbacks */
5195         VVnodeWriteToRead(&errorCode, targetptr);
5196         assert(!errorCode || errorCode == VSALVAGE);
5197         BreakCallBack(client->host, Fid, 0);
5198     }
5199
5200 Bad_ReleaseLock: 
5201     /* Put back file's vnode and volume */
5202     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5203
5204     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5205        errorCode = 0;              /* under our generous policy re RO vols */
5206
5207     ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
5208     return(errorCode);
5209
5210 } /*SAFSS_ReleaseLock*/
5211
5212
5213 afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall,
5214                                  struct AFSFid *Fid,
5215                                  struct AFSVolSync *Sync)
5216 {
5217     return SRXAFS_ReleaseLock(acall, Fid, Sync);
5218
5219 } /*SRXAFS_OldReleaseLock*/
5220
5221
5222 afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall,
5223                               struct AFSFid *Fid,
5224                               struct AFSVolSync *Sync)
5225 {
5226     afs_int32 code;
5227     struct rx_connection *tcon;
5228 #if FS_STATS_DETAILED
5229     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5230     struct timeval opStartTime,
5231                    opStopTime;              /* Start/stop times for RPC op*/
5232     struct timeval elapsedTime;             /* Transfer time */
5233
5234     /*
5235      * Set our stats pointer, remember when the RPC operation started, and
5236      * tally the operation.
5237      */
5238     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
5239     FS_LOCK
5240     (opP->numOps)++;
5241     FS_UNLOCK
5242     TM_GetTimeOfDay(&opStartTime, 0);
5243 #endif /* FS_STATS_DETAILED */
5244
5245     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5246         goto Bad_ReleaseLock;
5247
5248     code = SAFSS_ReleaseLock (acall, Fid, Sync);
5249     
5250 Bad_ReleaseLock:
5251     code = CallPostamble(tcon, code);
5252
5253 #if FS_STATS_DETAILED
5254     TM_GetTimeOfDay(&opStopTime, 0);
5255     if (code == 0) {
5256       FS_LOCK
5257       (opP->numSuccesses)++;
5258       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5259       fs_stats_AddTo((opP->sumTime), elapsedTime);
5260       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5261       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5262         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5263       }
5264       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5265         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5266       }
5267       FS_UNLOCK
5268     }
5269
5270 #endif /* FS_STATS_DETAILED */
5271
5272     osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
5273     return code;
5274
5275 } /*SRXAFS_ReleaseLock*/
5276
5277
5278 void SetSystemStats(struct AFSStatistics *stats)
5279 {
5280   /* Fix this sometime soon.. */
5281   /* Because hey, it's not like we have a network monitoring protocol... */
5282     struct      timeval time;
5283
5284     /* this works on all system types */
5285     TM_GetTimeOfDay(&time, 0);
5286     stats->CurrentTime = time.tv_sec;
5287 } /*SetSystemStats*/
5288
5289 void SetAFSStats(struct AFSStatistics *stats)
5290 {
5291     extern afs_int32 StartTime, CurrentConnections;
5292     int seconds;
5293
5294     FS_LOCK
5295     stats->CurrentMsgNumber = 0;
5296     stats->OldestMsgNumber = 0;
5297     stats->StartTime = StartTime;
5298     stats->CurrentConnections = CurrentConnections;
5299     stats->TotalAFSCalls = AFSCallStats.TotalCalls;
5300     stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
5301     stats->FetchDatas = AFSCallStats.FetchData;
5302     stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
5303     seconds = AFSCallStats.AccumFetchTime/1000;
5304     if (seconds <= 0) seconds = 1;
5305     stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
5306     stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
5307     stats->StoreDatas = AFSCallStats.StoreData;
5308     stats->StoredBytes = AFSCallStats.TotalStoredBytes;
5309     seconds = AFSCallStats.AccumStoreTime/1000;
5310     if (seconds <= 0) seconds = 1;
5311     stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
5312 #ifdef AFS_NT40_ENV
5313     stats->ProcessSize = -1; /* TODO: */
5314 #else
5315     stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
5316 #endif
5317     FS_UNLOCK
5318     h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
5319             (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
5320
5321 } /*SetAFSStats*/
5322
5323 /* Get disk related information from all AFS partitions. */
5324
5325 void SetVolumeStats(struct AFSStatistics *stats)
5326 {
5327     struct DiskPartition * part;
5328     int i = 0;
5329
5330     for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
5331         stats->Disks[i].TotalBlocks = part->totalUsable;
5332         stats->Disks[i].BlocksAvailable = part->free;
5333         memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
5334         strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
5335         i++;
5336     }
5337     while (i < AFS_MSTATDISKS) {
5338         stats->Disks[i].TotalBlocks = -1;
5339         i++;
5340     }
5341 } /*SetVolumeStats*/
5342
5343 afs_int32 SRXAFS_GetStatistics (struct rx_call *acall,
5344                                 struct ViceStatistics *Statistics)
5345 {
5346     afs_int32 code;
5347     struct rx_connection *tcon;
5348 #if FS_STATS_DETAILED
5349     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5350     struct timeval opStartTime,
5351                    opStopTime;              /* Start/stop times for RPC op*/
5352     struct timeval elapsedTime;             /* Transfer time */
5353
5354     /*
5355      * Set our stats pointer, remember when the RPC operation started, and
5356      * tally the operation.
5357      */
5358     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
5359     FS_LOCK
5360     (opP->numOps)++;
5361     FS_UNLOCK
5362     TM_GetTimeOfDay(&opStartTime, 0);
5363 #endif /* FS_STATS_DETAILED */
5364
5365     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
5366         goto Bad_GetStatistics;
5367
5368     ViceLog(1, ("SAFS_GetStatistics Received\n"));
5369     FS_LOCK
5370     AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
5371     FS_UNLOCK
5372     memset(Statistics, 0, sizeof(*Statistics));
5373     SetAFSStats((struct AFSStatistics *)Statistics);
5374     SetVolumeStats((struct AFSStatistics *)Statistics);
5375     SetSystemStats((struct AFSStatistics *)Statistics);
5376     
5377 Bad_GetStatistics:
5378     code = CallPostamble(tcon, code);
5379
5380 #if FS_STATS_DETAILED
5381     TM_GetTimeOfDay(&opStopTime, 0);
5382     if (code == 0) {
5383       FS_LOCK
5384       (opP->numSuccesses)++;
5385       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5386       fs_stats_AddTo((opP->sumTime), elapsedTime);
5387       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5388       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5389         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5390       }
5391       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5392         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5393       }
5394       FS_UNLOCK
5395     }
5396 #endif /* FS_STATS_DETAILED */
5397
5398     return code;
5399
5400 } /*SRXAFS_GetStatistics*/
5401
5402
5403 /*------------------------------------------------------------------------
5404  * EXPORTED SRXAFS_XStatsVersion
5405  *
5406  * Description:
5407  *      Routine called by the server-side RPC interface to implement
5408  *      pulling out the xstat version number for the File Server.
5409  *
5410  * Arguments:
5411  *      a_versionP : Ptr to the version number variable to set.
5412  *
5413  * Returns:
5414  *      0 (always)
5415  *
5416  * Environment:
5417  *      Nothing interesting.
5418  *
5419  * Side Effects:
5420  *      As advertised.
5421  *------------------------------------------------------------------------*/
5422
5423 afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
5424 { /*SRXAFS_XStatsVersion*/
5425
5426 #if FS_STATS_DETAILED
5427     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5428     struct timeval opStartTime,
5429                    opStopTime;              /* Start/stop times for RPC op*/
5430     struct timeval elapsedTime;             /* Transfer time */
5431
5432     /*
5433      * Set our stats pointer, remember when the RPC operation started, and
5434      * tally the operation.
5435      */
5436     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
5437     FS_LOCK
5438     (opP->numOps)++;
5439     FS_UNLOCK
5440     TM_GetTimeOfDay(&opStartTime, 0);
5441 #endif /* FS_STATS_DETAILED */
5442
5443     *a_versionP = AFS_XSTAT_VERSION;
5444
5445 #if FS_STATS_DETAILED
5446     TM_GetTimeOfDay(&opStopTime, 0);
5447     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5448     fs_stats_AddTo((opP->sumTime), elapsedTime);
5449     fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5450     if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5451         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5452     }
5453     if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5454         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5455     }
5456     FS_LOCK
5457     (opP->numSuccesses)++;
5458     FS_UNLOCK
5459 #endif /* FS_STATS_DETAILED */
5460
5461     return(0);
5462
5463 }  /*SRXAFS_XStatsVersion*/
5464
5465
5466 /*------------------------------------------------------------------------
5467  * PRIVATE FillPerfValues
5468  *
5469  * Description:
5470  *      Routine called to fill a regular performance data structure.
5471  *
5472  * Arguments:
5473  *      a_perfP : Ptr to perf structure to fill
5474  *
5475  * Returns:
5476  *      Nothing.
5477  *
5478  * Environment:
5479  *      Various collections need this info, so the guts were put in
5480  *      this separate routine.
5481  *
5482  * Side Effects:
5483  *      As advertised.
5484  *------------------------------------------------------------------------*/
5485
5486 static void FillPerfValues(struct afs_PerfStats *a_perfP)
5487 { /*FillPerfValues*/
5488
5489     int dir_Buffers;            /*# buffers in use by dir package*/
5490     int dir_Calls;              /*# read calls in dir package*/
5491     int dir_IOs;                /*# I/O ops in dir package*/
5492
5493     /*
5494      * Vnode cache section.
5495      */
5496     a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
5497     a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
5498     a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
5499     a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
5500     a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
5501     a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
5502     a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
5503     a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
5504     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
5505     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
5506     a_perfP->vcache_H_Entries = VolumeCacheSize;
5507     a_perfP->vcache_H_Gets = VolumeGets;
5508     a_perfP->vcache_H_Replacements = VolumeReplacements;
5509     
5510     /*
5511      * Directory section.
5512      */
5513     DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
5514     a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
5515     a_perfP->dir_Calls = (afs_int32 )dir_Calls;
5516     a_perfP->dir_IOs = (afs_int32) dir_IOs;
5517     
5518     /*
5519      * Rx section.
5520      */
5521     a_perfP->rx_packetRequests =
5522         (afs_int32) rx_stats.packetRequests;
5523     a_perfP->rx_noPackets_RcvClass =
5524         (afs_int32) rx_stats.receivePktAllocFailures;
5525     a_perfP->rx_noPackets_SendClass =
5526         (afs_int32) rx_stats.sendPktAllocFailures;
5527     a_perfP->rx_noPackets_SpecialClass =
5528         (afs_int32) rx_stats.specialPktAllocFailures;
5529     a_perfP->rx_socketGreedy =
5530         (afs_int32) rx_stats.socketGreedy;
5531     a_perfP->rx_bogusPacketOnRead =
5532         (afs_int32) rx_stats.bogusPacketOnRead;
5533     a_perfP->rx_bogusHost =
5534         (afs_int32) rx_stats.bogusHost;
5535     a_perfP->rx_noPacketOnRead =
5536         (afs_int32) rx_stats.noPacketOnRead;
5537     a_perfP->rx_noPacketBuffersOnRead =
5538         (afs_int32) rx_stats.noPacketBuffersOnRead;
5539     a_perfP->rx_selects =
5540         (afs_int32) rx_stats.selects;
5541     a_perfP->rx_sendSelects =
5542         (afs_int32) rx_stats.sendSelects;
5543     a_perfP->rx_packetsRead_RcvClass =
5544         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
5545     a_perfP->rx_packetsRead_SendClass =
5546         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
5547     a_perfP->rx_packetsRead_SpecialClass =
5548         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
5549     a_perfP->rx_dataPacketsRead =
5550         (afs_int32) rx_stats.dataPacketsRead;
5551     a_perfP->rx_ackPacketsRead =
5552         (afs_int32) rx_stats.ackPacketsRead;
5553     a_perfP->rx_dupPacketsRead =
5554         (afs_int32) rx_stats.dupPacketsRead;
5555     a_perfP->rx_spuriousPacketsRead =
5556         (afs_int32) rx_stats.spuriousPacketsRead;
5557     a_perfP->rx_packetsSent_RcvClass =
5558         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
5559     a_perfP->rx_packetsSent_SendClass =
5560         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
5561     a_perfP->rx_packetsSent_SpecialClass =
5562         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
5563     a_perfP->rx_ackPacketsSent =
5564         (afs_int32) rx_stats.ackPacketsSent;
5565     a_perfP->rx_pingPacketsSent =
5566         (afs_int32) rx_stats.pingPacketsSent;
5567     a_perfP->rx_abortPacketsSent =
5568         (afs_int32) rx_stats.abortPacketsSent;
5569     a_perfP->rx_busyPacketsSent =
5570         (afs_int32) rx_stats.busyPacketsSent;
5571     a_perfP->rx_dataPacketsSent =
5572         (afs_int32) rx_stats.dataPacketsSent;
5573     a_perfP->rx_dataPacketsReSent =
5574         (afs_int32) rx_stats.dataPacketsReSent;
5575     a_perfP->rx_dataPacketsPushed =
5576         (afs_int32) rx_stats.dataPacketsPushed;
5577     a_perfP->rx_ignoreAckedPacket =
5578         (afs_int32) rx_stats.ignoreAckedPacket;
5579     a_perfP->rx_totalRtt_Sec =
5580         (afs_int32) rx_stats.totalRtt.sec;
5581     a_perfP->rx_totalRtt_Usec =
5582         (afs_int32) rx_stats.totalRtt.usec;
5583     a_perfP->rx_minRtt_Sec =
5584         (afs_int32) rx_stats.minRtt.sec;
5585     a_perfP->rx_minRtt_Usec =
5586         (afs_int32) rx_stats.minRtt.usec;
5587     a_perfP->rx_maxRtt_Sec =
5588         (afs_int32) rx_stats.maxRtt.sec;
5589     a_perfP->rx_maxRtt_Usec =
5590         (afs_int32) rx_stats.maxRtt.usec;
5591     a_perfP->rx_nRttSamples =
5592         (afs_int32) rx_stats.nRttSamples;
5593     a_perfP->rx_nServerConns =
5594         (afs_int32) rx_stats.nServerConns;
5595     a_perfP->rx_nClientConns =
5596         (afs_int32) rx_stats.nClientConns;
5597     a_perfP->rx_nPeerStructs =
5598         (afs_int32) rx_stats.nPeerStructs;
5599     a_perfP->rx_nCallStructs =
5600         (afs_int32) rx_stats.nCallStructs;
5601     a_perfP->rx_nFreeCallStructs =
5602         (afs_int32) rx_stats.nFreeCallStructs;
5603     
5604     a_perfP->host_NumHostEntries = HTs;
5605     a_perfP->host_HostBlocks = HTBlocks;
5606     h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
5607                       &(a_perfP->host_HostsInSameNetOrSubnet),
5608                       &(a_perfP->host_HostsInDiffSubnet),
5609                       &(a_perfP->host_HostsInDiffNetwork));
5610     a_perfP->host_NumClients = CEs;
5611     a_perfP->host_ClientBlocks = CEBlocks;
5612     
5613     a_perfP->sysname_ID = afs_perfstats.sysname_ID;
5614
5615 } /*FillPerfValues*/
5616
5617
5618 /*------------------------------------------------------------------------
5619  * EXPORTED SRXAFS_GetXStats
5620  *
5621  * Description:
5622  *      Routine called by the server-side callback RPC interface to
5623  *      implement getting the given data collection from the extended
5624  *      File Server statistics.
5625  *
5626  * Arguments:
5627  *      a_call              : Ptr to Rx call on which this request came in.
5628  *      a_clientVersionNum  : Client version number.
5629  *      a_opCode            : Desired operation.
5630  *      a_serverVersionNumP : Ptr to version number to set.
5631  *      a_timeP             : Ptr to time value (seconds) to set.
5632  *      a_dataP             : Ptr to variable array structure to return
5633  *                            stuff in.
5634  *
5635  * Returns:
5636  *      0 (always).
5637  *
5638  * Environment:
5639  *      Nothing interesting.
5640  *
5641  * Side Effects:
5642  *      As advertised.
5643  *------------------------------------------------------------------------*/
5644
5645 afs_int32 SRXAFS_GetXStats(struct rx_call *a_call,
5646                            afs_int32 a_clientVersionNum,
5647                            afs_int32 a_collectionNumber,
5648                            afs_int32 *a_srvVersionNumP,
5649                            afs_int32 *a_timeP,
5650                            AFS_CollData *a_dataP)
5651 { /*SRXAFS_GetXStats*/
5652
5653     register int code;          /*Return value*/
5654     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
5655     afs_int32 dataBytes;                /*Bytes in data buffer*/
5656 #if FS_STATS_DETAILED
5657     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5658     struct timeval opStartTime,
5659                    opStopTime;              /* Start/stop times for RPC op*/
5660     struct timeval elapsedTime;             /* Transfer time */
5661
5662     /*
5663      * Set our stats pointer, remember when the RPC operation started, and
5664      * tally the operation.
5665      */
5666     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
5667     FS_LOCK
5668     (opP->numOps)++;
5669     FS_UNLOCK
5670     TM_GetTimeOfDay(&opStartTime, 0);
5671 #endif /* FS_STATS_DETAILED */
5672
5673     /*
5674      * Record the time of day and the server version number.
5675      */
5676     *a_srvVersionNumP = AFS_XSTAT_VERSION;
5677     *a_timeP = FT_ApproxTime();
5678
5679     /*
5680      * Stuff the appropriate data in there (assume victory)
5681      */
5682     code = 0;
5683
5684     ViceLog(1, ("Received GetXStats call for collection %d\n",  a_collectionNumber));
5685
5686 #if 0
5687     /*
5688      * We're not keeping stats, so just return successfully with
5689      * no data.
5690      */
5691     a_dataP->AFS_CollData_len = 0;
5692     a_dataP->AFS_CollData_val = NULL;
5693 #endif /* 0 */
5694
5695     switch(a_collectionNumber) {
5696       case AFS_XSTATSCOLL_CALL_INFO:
5697         /*
5698          * Pass back all the call-count-related data.
5699          *
5700          * >>> We are forced to allocate a separate area in which to
5701          * >>> put this stuff in by the RPC stub generator, since it
5702          * >>> will be freed at the tail end of the server stub code.
5703          */
5704 #if 0
5705         /*
5706          * I don't think call-level stats are being collected yet
5707          * for the File Server.
5708          */
5709         dataBytes = sizeof(struct afs_Stats);
5710         dataBuffP = (afs_int32 *)malloc(dataBytes);
5711         memcpy(dataBuffP, &afs_cmstats, dataBytes);
5712         a_dataP->AFS_CollData_len = dataBytes>>2;
5713         a_dataP->AFS_CollData_val = dataBuffP;
5714 #else
5715         a_dataP->AFS_CollData_len = 0;
5716         a_dataP->AFS_CollData_val = NULL;
5717 #endif /* 0 */
5718         break;
5719
5720       case AFS_XSTATSCOLL_PERF_INFO:
5721         /*
5722          * Pass back all the regular performance-related data.
5723          *
5724          * >>> We are forced to allocate a separate area in which to
5725          * >>> put this stuff in by the RPC stub generator, since it
5726          * >>> will be freed at the tail end of the server stub code.
5727          */
5728
5729         afs_perfstats.numPerfCalls++;
5730         FillPerfValues(&afs_perfstats);
5731
5732         /*
5733          * Don't overwrite the spares at the end.
5734          */
5735
5736         dataBytes = sizeof(struct afs_PerfStats);
5737         dataBuffP = (afs_int32 *)malloc(dataBytes);
5738         memcpy(dataBuffP, &afs_perfstats, dataBytes);
5739         a_dataP->AFS_CollData_len = dataBytes>>2;
5740         a_dataP->AFS_CollData_val = dataBuffP;
5741         break;
5742
5743       case AFS_XSTATSCOLL_FULL_PERF_INFO:
5744         /*
5745          * Pass back the full collection of performance-related data.
5746          * We have to stuff the basic, overall numbers in, but the
5747          * detailed numbers are kept in the structure already.
5748          *
5749          * >>> We are forced to allocate a separate area in which to
5750          * >>> put this stuff in by the RPC stub generator, since it
5751          * >>> will be freed at the tail end of the server stub code.
5752          */
5753
5754         afs_perfstats.numPerfCalls++;
5755 #if FS_STATS_DETAILED
5756         afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
5757         FillPerfValues(&afs_FullPerfStats.overall);
5758
5759         /*
5760          * Don't overwrite the spares at the end.
5761          */
5762
5763         dataBytes = sizeof(struct fs_stats_FullPerfStats);
5764         dataBuffP = (afs_int32 *)malloc(dataBytes);
5765         memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
5766         a_dataP->AFS_CollData_len = dataBytes>>2;
5767         a_dataP->AFS_CollData_val = dataBuffP;
5768 #endif
5769         break;
5770
5771       default:
5772         /*
5773          * Illegal collection number.
5774          */
5775         a_dataP->AFS_CollData_len = 0;
5776         a_dataP->AFS_CollData_val = NULL;
5777         code = 1;
5778     } /*Switch on collection number*/
5779
5780 #if FS_STATS_DETAILED
5781     TM_GetTimeOfDay(&opStopTime, 0);
5782     if (code == 0) {
5783       FS_LOCK
5784       (opP->numSuccesses)++;
5785       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5786       fs_stats_AddTo((opP->sumTime), elapsedTime);
5787       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5788       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5789         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5790       }
5791       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5792         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5793       }
5794       FS_UNLOCK
5795     }
5796
5797 #endif /* FS_STATS_DETAILED */
5798
5799     return(code);
5800
5801 } /*SRXAFS_GetXStats*/
5802
5803
5804 static afs_int32 common_GiveUpCallBacks (struct rx_call *acall,
5805                                          struct AFSCBFids *FidArray,
5806                                          struct AFSCBs *CallBackArray)
5807 {
5808     afs_int32 errorCode = 0;
5809     register int i;
5810     struct client *client;
5811     struct rx_connection *tcon;
5812 #if FS_STATS_DETAILED
5813     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5814     struct timeval opStartTime,
5815                    opStopTime;              /* Start/stop times for RPC op*/
5816     struct timeval elapsedTime;             /* Transfer time */
5817
5818     /*
5819      * Set our stats pointer, remember when the RPC operation started, and
5820      * tally the operation.
5821      */
5822     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
5823     FS_LOCK
5824     (opP->numOps)++;
5825     FS_UNLOCK
5826     TM_GetTimeOfDay(&opStartTime, 0);
5827 #endif /* FS_STATS_DETAILED */
5828
5829     if (FidArray)
5830         ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
5831
5832     FS_LOCK
5833     AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
5834     FS_UNLOCK
5835     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
5836         goto Bad_GiveUpCallBacks;
5837
5838     if (!FidArray && !CallBackArray) {
5839         ViceLog(1, ("SAFS_GiveUpAllCallBacks: host=%x\n", 
5840                 (tcon->peer ? tcon->peer->host : 0)));
5841         errorCode = GetClient(tcon, &client);
5842         if (!errorCode) 
5843             DeleteAllCallBacks_r(client->host, 1);
5844     } else {
5845         if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
5846             ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", 
5847                         FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, 
5848                         (tcon->peer ? tcon->peer->host : 0)));
5849             errorCode = EINVAL;
5850             goto Bad_GiveUpCallBacks;
5851         }
5852
5853         errorCode = GetClient(tcon, &client);
5854         if (!errorCode) {
5855             for (i=0; i < FidArray->AFSCBFids_len; i++) {
5856                 register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
5857                 DeleteCallBack(client->host, fid);
5858             }
5859         }
5860     }
5861
5862 Bad_GiveUpCallBacks:
5863     errorCode = CallPostamble(tcon, errorCode);
5864
5865 #if FS_STATS_DETAILED
5866     TM_GetTimeOfDay(&opStopTime, 0);
5867     if (errorCode == 0) {
5868       FS_LOCK
5869       (opP->numSuccesses)++;
5870       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5871       fs_stats_AddTo((opP->sumTime), elapsedTime);
5872       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5873       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5874         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5875       }
5876       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5877         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5878       }
5879       FS_UNLOCK
5880     }
5881 #endif /* FS_STATS_DETAILED */
5882 out:
5883     return errorCode;
5884
5885 } /*common_GiveUpCallBacks*/
5886
5887
5888 afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall,
5889                                   struct AFSCBFids *FidArray,
5890                                   struct AFSCBs *CallBackArray)
5891 {
5892     return common_GiveUpCallBacks(acall, FidArray, CallBackArray);
5893 } /*SRXAFS_GiveUpCallBacks*/
5894
5895 afs_int32 SRXAFS_GiveUpAllCallBacks (struct rx_call *acall)
5896 {
5897     return common_GiveUpCallBacks(acall, 0, 0);
5898 } /*SRXAFS_GiveUpAllCallBacks*/
5899
5900
5901 afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall,
5902                                  char *avolid,
5903                                  struct AFSVolumeInfo *avolinfo)
5904 {
5905     return(VNOVOL);             /* XXX Obsolete routine XXX */
5906
5907 } /*SRXAFS_NGetVolumeInfo*/
5908
5909
5910 /*
5911  * Dummy routine. Should never be called (the cache manager should only 
5912  * invoke this interface when communicating with a AFS/DFS Protocol
5913  * Translator).
5914  */
5915 afs_int32 SRXAFS_Lookup(struct rx_call *call_p,
5916                         struct AFSFid *afs_dfid_p,
5917                         char *afs_name_p,
5918                         struct AFSFid *afs_fid_p,
5919                         struct AFSFetchStatus *afs_status_p,
5920                         struct AFSFetchStatus *afs_dir_status_p,
5921                         struct AFSCallBack *afs_callback_p,
5922                         struct AFSVolSync *afs_sync_p)
5923 {
5924     return EINVAL;
5925 }
5926
5927
5928 afs_int32 SRXAFS_GetCapabilities(struct rx_call *acall,
5929                                  Capabilities *capabilities)
5930 {
5931     afs_int32 *dataBuffP;               
5932     afs_int32 *dataP;
5933     afs_int32 dataBytes;   
5934
5935     dataBytes = 1 * sizeof(afs_int32);
5936     dataBuffP = (afs_int32 *)malloc(dataBytes);
5937     dataBuffP[0] = CAPABILITY_ERRORTRANS;
5938     capabilities->Capabilities_len = dataBytes/sizeof(afs_int32);
5939     capabilities->Capabilities_val = dataBuffP;
5940
5941     return 0;
5942
5943
5944 afs_int32 SRXAFS_FlushCPS(struct rx_call *acall,
5945                           struct ViceIds *vids,
5946                           struct IPAddrs *addrs,
5947                           afs_int32 spare1,
5948                           afs_int32 *spare2, 
5949                           afs_int32 *spare3)
5950 {
5951     int i;
5952     afs_int32 nids, naddrs;
5953     afs_int32 *vd, *addr;
5954     int     errorCode = 0;              /* return code to caller */
5955     struct client *client;
5956     struct rx_connection *tcon = rx_ConnectionOf(acall);
5957
5958     ViceLog(1, ("SRXAFS_FlushCPS\n"));
5959     FS_LOCK
5960     AFSCallStats.TotalCalls++;
5961     FS_UNLOCK
5962     nids = vids->ViceIds_len;   /* # of users in here */
5963     naddrs = addrs->IPAddrs_len;        /* # of hosts in here */
5964     if (nids < 0 || naddrs < 0) {
5965         errorCode = EINVAL;
5966         goto Bad_FlushCPS;
5967     }
5968
5969     vd = vids->ViceIds_val;
5970     for (i=0; i<nids; i++, vd++) {
5971       if (!*vd)
5972         continue;
5973       client = h_ID2Client(*vd);  /* returns client locked, or NULL */
5974       if (!client)
5975         continue;
5976
5977       BoostSharedLock(&client->lock);
5978       client->prfail = 2;       /* Means re-eval client's cps */
5979 #ifdef  notdef
5980       if (client->tcon) {
5981         rx_SetRock(((struct rx_connection *) client->tcon), 0);
5982       }
5983 #endif
5984       if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
5985         free(client->CPS.prlist_val);
5986         client->CPS.prlist_val = NULL;
5987         client->CPS.prlist_len = 0;
5988       }
5989       ReleaseWriteLock(&client->lock);
5990     }
5991
5992     addr = addrs->IPAddrs_val;
5993     for (i=0; i<naddrs; i++, addr++) {
5994       if (*addr)
5995         h_flushhostcps(*addr, htons(7001));
5996     }
5997
5998 Bad_FlushCPS:
5999     ViceLog(2, ("SAFS_FlushCPS  returns %d\n", errorCode)); 
6000     return errorCode;
6001 } /*SRXAFS_FlushCPS */
6002
6003 /* worthless hack to let CS keep running ancient software */
6004 static int afs_vtoi(register char *aname)
6005 {
6006     register afs_int32 temp;
6007     register int tc;
6008
6009     temp = 0;
6010     while((tc = *aname++)) {
6011         if (tc > '9' || tc < '0') return 0; /* invalid name */
6012         temp *= 10;
6013         temp += tc - '0';
6014     }
6015     return temp;
6016 }
6017
6018 /*
6019  * may get name or #, but must handle all weird cases (recognize readonly
6020  * or backup volumes by name or #
6021  */
6022 static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave,
6023                                  register struct VolumeInfo *av)
6024 {
6025     register int i, j, vol;
6026     afs_int32 mask, whichType;
6027     afs_uint32 *serverHost, *typePtr;
6028     
6029     /* figure out what type we want if by name */
6030     i = strlen(aname);
6031     if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
6032         whichType = BACKVOL;
6033     else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
6034         whichType = ROVOL;
6035     else whichType = RWVOL;
6036     
6037     vol = afs_vtoi(aname);
6038     if (vol == 0) vol = ave->volumeId[whichType];
6039     
6040     /*
6041      * Now vol has volume # we're interested in.  Next, figure out the type
6042      * of the volume by looking finding it in the vldb entry
6043      */
6044     if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
6045         mask = VLSF_RWVOL;
6046         whichType = RWVOL;
6047     }
6048     else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
6049         mask = VLSF_ROVOL;
6050         whichType = ROVOL;
6051     }
6052     else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
6053         mask = VLSF_RWVOL;  /* backup always is on the same volume as parent */
6054         whichType = BACKVOL;
6055     }
6056     else
6057         return  EINVAL;     /* error: can't find volume in vldb entry */
6058     
6059     typePtr = &av->Type0;
6060     serverHost = &av->Server0;
6061     av->Vid = vol;
6062     av->Type = whichType;
6063     av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
6064     if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
6065     if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
6066     if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
6067
6068     for(i=0,j=0; i<ave->nServers; i++) {
6069         if ((ave->serverFlags[i] & mask) == 0) continue;    /* wrong volume */
6070         serverHost[j] = ave->serverNumber[i];
6071         j++;
6072     }
6073     av->ServerCount = j;
6074     if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
6075     return 0;
6076 }
6077
6078 static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo)
6079 {
6080     static struct rx_connection *vlConn = 0;
6081     static int down = 0;
6082     static afs_int32 lastDownTime = 0;
6083     struct vldbentry tve;
6084     struct rx_securityClass *vlSec;
6085     register afs_int32 code;
6086
6087     if (!vlConn) {
6088         vlSec = rxnull_NewClientSecurityObject();
6089         vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
6090         rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
6091     }
6092     if (down && (FT_ApproxTime() < lastDownTime + 180)) {
6093         return 1;   /* failure */
6094     }
6095
6096     code = VL_GetEntryByNameO(vlConn, avolid, &tve);
6097     if (code >= 0) down = 0;    /* call worked */
6098     if (code) {
6099         if (code < 0) {
6100             lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
6101             down = 1;
6102         }
6103         return code;
6104     }
6105
6106     /* otherwise convert to old format vldb entry */
6107     code = CopyVolumeEntry(avolid, &tve, avolinfo);
6108     return code;
6109 }
6110
6111
6112
6113
6114
6115
6116 afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall,
6117                                 char *avolid,
6118                                 struct VolumeInfo *avolinfo)
6119 {
6120     afs_int32 code;
6121     struct rx_connection *tcon;
6122 #if FS_STATS_DETAILED
6123     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6124     struct timeval opStartTime,
6125                    opStopTime;              /* Start/stop times for RPC op*/
6126     struct timeval elapsedTime;             /* Transfer time */
6127
6128     /*
6129      * Set our stats pointer, remember when the RPC operation started, and
6130      * tally the operation.
6131      */
6132     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
6133     FS_LOCK
6134     (opP->numOps)++;
6135     FS_UNLOCK
6136     TM_GetTimeOfDay(&opStartTime, 0);
6137 #endif /* FS_STATS_DETAILED */
6138     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6139         goto Bad_GetVolumeInfo;
6140
6141     FS_LOCK
6142     AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
6143     FS_UNLOCK
6144
6145     code = TryLocalVLServer(avolid, avolinfo);
6146     ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
6147                 code, avolinfo->Vid, avolinfo->Type,
6148                 avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
6149                 avolinfo->Server3));
6150     avolinfo->Type4     = 0xabcd9999;   /* tell us to try new vldb */
6151
6152 Bad_GetVolumeInfo:
6153     code = CallPostamble(tcon, code);
6154
6155 #if FS_STATS_DETAILED
6156     TM_GetTimeOfDay(&opStopTime, 0);
6157     if (code == 0) {
6158       FS_LOCK
6159       (opP->numSuccesses)++;
6160       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6161       fs_stats_AddTo((opP->sumTime), elapsedTime);
6162       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6163       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6164         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6165       }
6166       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6167         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6168       }
6169       FS_UNLOCK
6170     }
6171
6172 #endif /* FS_STATS_DETAILED */
6173
6174     return code;
6175
6176 } /*SRXAFS_GetVolumeInfo*/
6177
6178
6179 afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall,
6180                                  afs_int32 avolid,
6181                                  AFSFetchVolumeStatus *FetchVolStatus,
6182                                  char **Name,
6183                                  char **OfflineMsg,
6184                                  char **Motd)
6185 {
6186     Vnode * targetptr = 0;              /* vnode of the new file */
6187     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6188     int     errorCode = 0;              /* error code */
6189     Volume * volptr = 0;                /* pointer to the volume header */
6190     struct client * client;             /* pointer to client entry */
6191     afs_int32 rights, anyrights;                /* rights for this and any user */
6192     AFSFid  dummyFid;
6193     struct rx_connection *tcon;
6194 #if FS_STATS_DETAILED
6195     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6196     struct timeval opStartTime,
6197                    opStopTime;              /* Start/stop times for RPC op*/
6198     struct timeval elapsedTime;             /* Transfer time */
6199
6200     /*
6201      * Set our stats pointer, remember when the RPC operation started, and
6202      * tally the operation.
6203      */
6204     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
6205     FS_LOCK
6206     (opP->numOps)++;
6207     FS_UNLOCK
6208     TM_GetTimeOfDay(&opStartTime, 0);
6209 #endif /* FS_STATS_DETAILED */
6210
6211     ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
6212     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6213         goto Bad_GetVolumeStatus;
6214
6215     FS_LOCK
6216     AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
6217     FS_UNLOCK
6218
6219     if (avolid == 0) {
6220         errorCode = EINVAL;
6221         goto Bad_GetVolumeStatus;
6222     }
6223     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6224
6225     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6226                                      MustBeDIR, &parentwhentargetnotdir,
6227                                      &client, READ_LOCK, &rights, &anyrights)))
6228         goto Bad_GetVolumeStatus;
6229
6230     if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
6231         errorCode = EACCES;
6232         goto Bad_GetVolumeStatus;
6233     }
6234     RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
6235
6236 Bad_GetVolumeStatus:
6237     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6238     ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
6239     /* next is to guarantee out strings exist for stub */
6240     if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
6241     if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
6242     if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
6243     errorCode = CallPostamble(tcon, errorCode);
6244
6245 #if FS_STATS_DETAILED
6246     TM_GetTimeOfDay(&opStopTime, 0);
6247     if (errorCode == 0) {
6248       FS_LOCK
6249       (opP->numSuccesses)++;
6250       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6251       fs_stats_AddTo((opP->sumTime), elapsedTime);
6252       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6253       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6254         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6255       }
6256       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6257         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6258       }
6259       FS_UNLOCK
6260     }
6261
6262 #endif /* FS_STATS_DETAILED */
6263     return(errorCode);
6264
6265 } /*SRXAFS_GetVolumeStatus*/
6266
6267
6268 afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall,
6269                                   afs_int32 avolid,
6270                                   AFSStoreVolumeStatus *StoreVolStatus,
6271                                   char *Name,
6272                                   char *OfflineMsg,
6273                                   char *Motd)
6274 {
6275     Vnode * targetptr = 0;              /* vnode of the new file */
6276     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6277     int     errorCode = 0;              /* error code */
6278     Volume * volptr = 0;                /* pointer to the volume header */
6279     struct client * client;             /* pointer to client entry */
6280     afs_int32 rights, anyrights;                /* rights for this and any user */
6281     AFSFid  dummyFid;
6282     struct rx_connection *tcon = rx_ConnectionOf(acall);
6283 #if FS_STATS_DETAILED
6284     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6285     struct timeval opStartTime,
6286                    opStopTime;              /* Start/stop times for RPC op*/
6287     struct timeval elapsedTime;             /* Transfer time */
6288
6289     /*
6290      * Set our stats pointer, remember when the RPC operation started, and
6291      * tally the operation.
6292      */
6293     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
6294     FS_LOCK
6295     (opP->numOps)++;
6296     FS_UNLOCK
6297     TM_GetTimeOfDay(&opStartTime, 0);
6298 #endif /* FS_STATS_DETAILED */
6299
6300     ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
6301     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6302         goto Bad_SetVolumeStatus;
6303
6304     FS_LOCK
6305     AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
6306     FS_UNLOCK
6307
6308     if (avolid == 0) {
6309         errorCode = EINVAL;
6310         goto Bad_SetVolumeStatus;
6311     }
6312     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6313
6314     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6315                                      MustBeDIR, &parentwhentargetnotdir,
6316                                      &client, READ_LOCK, &rights, &anyrights)))
6317         goto Bad_SetVolumeStatus;
6318
6319     if (readonlyServer) {
6320         errorCode = VREADONLY;
6321         goto Bad_SetVolumeStatus;
6322     }
6323     if (VanillaUser(client)) {
6324         errorCode = EACCES;
6325         goto Bad_SetVolumeStatus;
6326     }
6327
6328     errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
6329                                       OfflineMsg, Motd);
6330
6331  Bad_SetVolumeStatus:
6332     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6333     ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
6334     errorCode = CallPostamble(tcon, errorCode);
6335
6336 #if FS_STATS_DETAILED
6337     TM_GetTimeOfDay(&opStopTime, 0);
6338     if (errorCode == 0) {
6339       FS_LOCK
6340       (opP->numSuccesses)++;
6341       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6342       fs_stats_AddTo((opP->sumTime), elapsedTime);
6343       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6344       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6345         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6346       }
6347       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6348         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6349       }
6350       FS_UNLOCK
6351     }
6352
6353 #endif /* FS_STATS_DETAILED */
6354
6355     osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
6356     return(errorCode);
6357
6358 } /*SRXAFS_SetVolumeStatus*/
6359
6360 #define DEFAULTVOLUME   "root.afs"
6361
6362 afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName)
6363 {
6364     int fd;
6365     int len;
6366     char *temp;
6367     int errorCode = 0;          /* error code */
6368     struct rx_connection *tcon;
6369 #if FS_STATS_DETAILED
6370     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6371     struct timeval opStartTime,
6372                    opStopTime;              /* Start/stop times for RPC op*/
6373     struct timeval elapsedTime;             /* Transfer time */
6374
6375     /*
6376      * Set our stats pointer, remember when the RPC operation started, and
6377      * tally the operation.
6378      */
6379     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
6380     FS_LOCK
6381     (opP->numOps)++;
6382     FS_UNLOCK
6383     TM_GetTimeOfDay(&opStartTime, 0);
6384 #endif /* FS_STATS_DETAILED */
6385
6386     return FSERR_EOPNOTSUPP;
6387
6388 #ifdef  notdef
6389     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
6390         goto Bad_GetRootVolume;
6391     FS_LOCK
6392     AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
6393     FS_UNLOCK
6394
6395     temp = malloc(256);
6396     fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
6397     if (fd <= 0)
6398         strcpy(temp, DEFAULTVOLUME);
6399     else {
6400 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6401         lockf(fd, F_LOCK, 0);
6402 #else
6403         flock(fd, LOCK_EX);
6404 #endif
6405         len = read(fd, temp, 256);
6406 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6407         lockf(fd, F_ULOCK, 0);
6408 #else
6409         flock(fd, LOCK_UN);
6410 #endif
6411         close(fd);
6412         if (temp[len-1] == '\n') len--;
6413         temp[len] = '\0';
6414     }
6415     *VolumeName = temp;     /* freed by rx server-side stub */
6416
6417 Bad_GetRootVolume:
6418     errorCode = CallPostamble(tcon, errorCode);
6419
6420 #if FS_STATS_DETAILED
6421     TM_GetTimeOfDay(&opStopTime, 0);
6422     if (errorCode == 0) {
6423       FS_LOCK
6424       (opP->numSuccesses)++;
6425       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6426       fs_stats_AddTo((opP->sumTime), elapsedTime);
6427       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6428       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6429         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6430       }
6431       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6432         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6433       }
6434       FS_UNLOCK
6435     }
6436 #endif /* FS_STATS_DETAILED */
6437
6438     return(errorCode);
6439 #endif  /* notdef */
6440
6441 } /*SRXAFS_GetRootVolume*/
6442
6443
6444 /* still works because a struct CBS is the same as a struct AFSOpaque */
6445 afs_int32 SRXAFS_CheckToken (struct rx_call *acall,
6446                              afs_int32 AfsId,
6447                              struct AFSOpaque *Token)
6448 {
6449     afs_int32 code;
6450     struct rx_connection *tcon;
6451 #if FS_STATS_DETAILED
6452     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6453     struct timeval opStartTime,
6454                    opStopTime;              /* Start/stop times for RPC op*/
6455     struct timeval elapsedTime;             /* Transfer time */
6456
6457     /*
6458      * Set our stats pointer, remember when the RPC operation started, and
6459      * tally the operation.
6460      */
6461     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
6462     FS_LOCK
6463     (opP->numOps)++;
6464     FS_UNLOCK
6465     TM_GetTimeOfDay(&opStartTime, 0);
6466 #endif /* FS_STATS_DETAILED */
6467
6468     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6469         goto Bad_CheckToken;
6470
6471     code = FSERR_ECONNREFUSED;
6472     
6473 Bad_CheckToken:
6474     code = CallPostamble(tcon, code);
6475
6476 #if FS_STATS_DETAILED
6477     TM_GetTimeOfDay(&opStopTime, 0);
6478     if (code == 0) {
6479       FS_LOCK
6480       (opP->numSuccesses)++;
6481       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6482       fs_stats_AddTo((opP->sumTime), elapsedTime);
6483       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6484       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6485         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6486       }
6487       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6488         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6489       }
6490       FS_UNLOCK
6491     }
6492
6493 #endif /* FS_STATS_DETAILED */
6494
6495     return code;
6496
6497 } /*SRXAFS_CheckToken*/
6498
6499 afs_int32 SRXAFS_GetTime (struct rx_call *acall,
6500                           afs_uint32 *Seconds,
6501                           afs_uint32 *USeconds)
6502 {
6503     afs_int32 code;
6504     struct rx_connection *tcon;
6505     struct timeval tpl;
6506 #if FS_STATS_DETAILED
6507     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6508     struct timeval opStartTime,
6509                    opStopTime;              /* Start/stop times for RPC op*/
6510     struct timeval elapsedTime;             /* Transfer time */
6511
6512     /*
6513      * Set our stats pointer, remember when the RPC operation started, and
6514      * tally the operation.
6515      */
6516     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
6517     FS_LOCK
6518     (opP->numOps)++;
6519     FS_UNLOCK
6520     TM_GetTimeOfDay(&opStartTime, 0);
6521 #endif /* FS_STATS_DETAILED */
6522
6523     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
6524         goto Bad_GetTime;
6525
6526     FS_LOCK
6527     AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
6528     FS_UNLOCK
6529
6530     TM_GetTimeOfDay(&tpl, 0);
6531     *Seconds = tpl.tv_sec;
6532     *USeconds = tpl.tv_usec;
6533
6534     ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
6535     
6536 Bad_GetTime:
6537     code = CallPostamble(tcon, code);
6538
6539 #if FS_STATS_DETAILED
6540     TM_GetTimeOfDay(&opStopTime, 0);
6541     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6542     if (code == 0) {
6543       FS_LOCK
6544       (opP->numSuccesses)++;
6545       fs_stats_AddTo((opP->sumTime), elapsedTime);
6546       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6547       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6548         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6549       }
6550       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6551         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6552       }
6553       FS_UNLOCK
6554     }
6555
6556 #endif /* FS_STATS_DETAILED */
6557
6558     return code;
6559
6560 } /*SRXAFS_GetTime*/
6561
6562
6563 /*
6564  * FetchData_RXStyle
6565  *
6566  * Purpose:
6567  *      Implement a client's data fetch using Rx.
6568  *
6569  * Arguments:
6570  *      volptr          : Ptr to the given volume's info.
6571  *      targetptr       : Pointer to the vnode involved.
6572  *      Call            : Ptr to the Rx call involved.
6573  *      Pos             : Offset within the file.
6574  *      Len             : Length in bytes to read; this value is bogus!
6575  * if FS_STATS_DETAILED
6576  *      a_bytesToFetchP : Set to the number of bytes to be fetched from
6577  *                        the File Server.
6578  *      a_bytesFetchedP : Set to the actual number of bytes fetched from
6579  *                        the File Server.
6580  * endif
6581  */
6582
6583 afs_int32
6584 FetchData_RXStyle(Volume *volptr, 
6585                   Vnode *targetptr, 
6586                   register struct rx_call *Call,
6587                   afs_int32 Pos,
6588                   afs_int32 Len,
6589                   afs_int32 Int64Mode,
6590 #if FS_STATS_DETAILED
6591                   afs_int32 *a_bytesToFetchP,
6592                   afs_int32 *a_bytesFetchedP
6593 #endif /* FS_STATS_DETAILED */
6594                   )
6595 {
6596     struct timeval StartTime, StopTime; /* used to calculate file  transfer rates */
6597     int errorCode = 0;                  /* Returned error code to caller */
6598     int code;
6599     IHandle_t *ihP;
6600     FdHandle_t *fdP;
6601 #ifdef AFS_NT40_ENV
6602     register char *tbuffer;
6603 #else /* AFS_NT40_ENV */
6604     struct iovec tiov[RX_MAXIOVECS];
6605     int tnio;
6606 #endif /* AFS_NT40_ENV */
6607     afs_int32 tlen;
6608     afs_int32 optSize;
6609     struct stat tstat;
6610 #ifdef  AFS_AIX_ENV
6611     struct statfs tstatfs;
6612 #endif
6613
6614 #if FS_STATS_DETAILED
6615     /*
6616      * Initialize the byte count arguments.
6617      */
6618     (*a_bytesToFetchP) = 0;
6619     (*a_bytesFetchedP) = 0;
6620 #endif /* FS_STATS_DETAILED */
6621
6622     if (!VN_GET_INO(targetptr)) {
6623         /*
6624          * This is used for newly created files; we simply send 0 bytes
6625          * back to make the cache manager happy...
6626          */
6627         tlen = htonl(0);
6628         if (Int64Mode)
6629             rx_Write(Call, (char *)&tlen, sizeof(afs_int32));   /* send 0-length  */
6630         rx_Write(Call, (char *)&tlen, sizeof(afs_int32));       /* send 0-length  */
6631         return (0);
6632     }
6633     TM_GetTimeOfDay(&StartTime, 0);
6634     ihP = targetptr->handle;
6635     fdP = IH_OPEN(ihP);
6636     if (fdP == NULL) return EIO;
6637     optSize = sendBufSize;
6638     tlen = FDH_SIZE(fdP);
6639     if (tlen < 0) {
6640         FDH_CLOSE(fdP);
6641         return EIO;
6642     }
6643
6644     if (Pos + Len > tlen) Len = tlen - Pos;     /* get length we should send */
6645     FDH_SEEK(fdP, Pos, 0);
6646     tlen = htonl(Len);
6647     if (Int64Mode) {
6648         afs_int32 zero = 0;
6649         rx_Write(Call, (char *)&zero, sizeof(afs_int32)); /* High order bits */
6650     }
6651     rx_Write(Call, (char *)&tlen, sizeof(afs_int32));   /* send length on fetch */
6652 #if FS_STATS_DETAILED
6653     (*a_bytesToFetchP) = Len;
6654 #endif /* FS_STATS_DETAILED */
6655 #ifdef AFS_NT40_ENV
6656     tbuffer = AllocSendBuffer();
6657 #endif /* AFS_NT40_ENV */
6658     while (Len > 0) {
6659         if (Len > optSize) tlen = optSize;
6660         else tlen = Len;
6661 #ifdef AFS_NT40_ENV
6662         errorCode = FDH_READ(fdP, tbuffer, tlen);
6663         if (errorCode != tlen) {
6664             FDH_CLOSE(fdP);
6665             FreeSendBuffer((struct afs_buffer *) tbuffer);
6666             return EIO;
6667         }
6668         errorCode = rx_Write(Call, tbuffer, tlen);
6669 #else /* AFS_NT40_ENV */
6670         errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6671         if (errorCode <= 0) {
6672             FDH_CLOSE(fdP);
6673             return EIO;
6674         }
6675         tlen = errorCode;
6676         errorCode = FDH_READV(fdP, tiov, tnio);
6677         if (errorCode != tlen) {
6678             FDH_CLOSE(fdP);
6679             return EIO;
6680         }
6681         errorCode = rx_Writev(Call, tiov, tnio, tlen);
6682 #endif /* AFS_NT40_ENV */
6683 #if FS_STATS_DETAILED
6684         /*
6685           * Bump the number of bytes actually sent by the number from this
6686           * latest iteration
6687           */
6688         (*a_bytesFetchedP) += errorCode;
6689 #endif /* FS_STATS_DETAILED */
6690         if (errorCode != tlen) {
6691             FDH_CLOSE(fdP);
6692 #ifdef AFS_NT40_ENV
6693             FreeSendBuffer((struct afs_buffer *) tbuffer);
6694 #endif /* AFS_NT40_ENV */
6695             return -31;
6696         }
6697         Len -= tlen;
6698     }
6699 #ifdef AFS_NT40_ENV
6700     FreeSendBuffer((struct afs_buffer *) tbuffer);
6701 #endif /* AFS_NT40_ENV */
6702     FDH_CLOSE(fdP);
6703     TM_GetTimeOfDay(&StopTime, 0);
6704
6705     /* Adjust all Fetch Data related stats */
6706     FS_LOCK
6707     if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
6708         AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
6709     AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
6710       ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
6711     AFSCallStats.TotalFetchedBytes += targetptr->disk.length;
6712     AFSCallStats.FetchSize1++;
6713     if (targetptr->disk.length < SIZE2)
6714         AFSCallStats.FetchSize2++;  
6715     else if (targetptr->disk.length < SIZE3)
6716         AFSCallStats.FetchSize3++;
6717     else if (targetptr->disk.length < SIZE4)
6718         AFSCallStats.FetchSize4++;  
6719     else
6720         AFSCallStats.FetchSize5++;
6721     FS_UNLOCK
6722     return (0);
6723
6724 } /*FetchData_RXStyle*/
6725
6726 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, int *size)
6727 {
6728 #ifdef AFS_NAMEI_ENV
6729     FdHandle_t *lhp;
6730     lhp = IH_OPEN(V_linkHandle(vp));
6731     if (!lhp)
6732         return EIO;
6733 #ifdef AFS_NT40_ENV
6734     *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6735 #else
6736     *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6737 #endif
6738     FDH_CLOSE(lhp);
6739     if (*lc < 0 )
6740         return -1;
6741     *size = OS_SIZE(fdP->fd_fd);
6742     return (*size == -1) ? -1 : 0;
6743 #else
6744     struct stat status;
6745
6746     if (fstat(fdP->fd_fd, &status)<0) {
6747         return -1;
6748     }
6749
6750     *lc = GetLinkCount(vp, &status);
6751     *size = status.st_size;
6752     return 0;
6753 #endif   
6754 }
6755
6756 /*
6757  * StoreData_RXStyle
6758  *
6759  * Purpose:
6760  *      Implement a client's data store using Rx.
6761  *
6762  * Arguments:
6763  *      volptr          : Ptr to the given volume's info.
6764  *      targetptr       : Pointer to the vnode involved.
6765  *      Call            : Ptr to the Rx call involved.
6766  *      Pos             : Offset within the file.
6767  *      Len             : Length in bytes to store; this value is bogus!
6768  * if FS_STATS_DETAILED
6769  *      a_bytesToStoreP : Set to the number of bytes to be stored to
6770  *                        the File Server.
6771  *      a_bytesStoredP  : Set to the actual number of bytes stored to
6772  *                        the File Server.
6773  * endif
6774  */
6775 afs_int32
6776 StoreData_RXStyle(Volume *volptr,
6777                   Vnode *targetptr,
6778                   struct AFSFid *Fid,
6779                   struct client *client,
6780                   register struct rx_call *Call,
6781                   afs_uint32 Pos,
6782                   afs_uint32 Length,
6783                   afs_uint32 FileLength,
6784                   int sync,
6785 #if FS_STATS_DETAILED
6786                   afs_int32 *a_bytesToStoreP,
6787                   afs_int32 *a_bytesStoredP
6788 #endif /* FS_STATS_DETAILED */
6789                   )
6790 {
6791     int     bytesTransfered;            /* number of bytes actually transfered */
6792     struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
6793     int errorCode = 0;                  /* Returned error code to caller */
6794 #ifdef AFS_NT40_ENV
6795     register char *tbuffer;             /* data copying buffer */
6796 #else /* AFS_NT40_ENV */
6797     struct iovec tiov[RX_MAXIOVECS];    /* no data copying with iovec */
6798     int tnio;                           /* temp for iovec size */
6799 #endif /* AFS_NT40_ENV */
6800     int tlen;                           /* temp for xfr length */
6801     Inode tinode;                       /* inode for I/O */
6802     afs_int32 optSize;                  /* optimal transfer size */
6803     int DataLength;                     /* size of inode */
6804     afs_int32 TruncatedLength;          /* size after ftruncate */
6805     afs_uint32 NewLength;               /* size after this store completes */
6806     afs_int32 adjustSize;               /* bytes to call VAdjust... with */
6807     int linkCount;                      /* link count on inode */
6808     int code;
6809     FdHandle_t *fdP;
6810     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
6811
6812 #if FS_STATS_DETAILED
6813     /*
6814      * Initialize the byte count arguments.
6815      */
6816     (*a_bytesToStoreP) = 0;
6817     (*a_bytesStoredP)  = 0;
6818 #endif /* FS_STATS_DETAILED */
6819
6820     /*
6821      * We break the callbacks here so that the following signal will not
6822      * leave a window.
6823      */
6824     BreakCallBack(client->host, Fid, 0);
6825
6826     if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
6827         /* the inode should have been created in Alloc_NewVnode */
6828         logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
6829         ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
6830                 Fid->Volume, Fid->Vnode, Fid->Unique, 
6831                 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
6832         return ENOENT;  /* is this proper error code? */
6833     }
6834     else {
6835         /*
6836          * See if the file has several links (from other volumes).  If it
6837          * does, then we have to make a copy before changing it to avoid
6838          *changing read-only clones of this dude
6839          */
6840         ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
6841                      PrintInode(NULL, VN_GET_INO(targetptr))));
6842         fdP = IH_OPEN(targetptr->handle);
6843         if (fdP == NULL) 
6844             return ENOENT;
6845         if (GetLinkCountAndSize(volptr, fdP, &linkCount,
6846                                 &DataLength)<0) {
6847             FDH_CLOSE(fdP);
6848             return EIO;
6849         }
6850         
6851         if (linkCount != 1) {
6852             afs_uint32 size;
6853             ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
6854                          PrintInode(NULL, VN_GET_INO(targetptr))));
6855             /* other volumes share this data, better copy it first */
6856
6857             /* Adjust the disk block count by the creation of the new inode.
6858              * We call the special VDiskUsage so we don't adjust the volume's
6859              * quota since we don't want to penalyze the user for afs's internal
6860              * mechanisms (i.e. copy on write overhead.) Also the right size
6861              * of the disk will be recorded...
6862              */
6863             FDH_CLOSE(fdP);
6864             size = targetptr->disk.length;
6865             volptr->partition->flags &= ~PART_DONTUPDATE;
6866             VSetPartitionDiskUsage(volptr->partition);
6867             volptr->partition->flags |= PART_DONTUPDATE;
6868             if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
6869                 volptr->partition->flags &= ~PART_DONTUPDATE;
6870                 return(errorCode);
6871             }
6872
6873             ViceLog(25, ("StoreData : calling CopyOnWrite on  target dir\n"));
6874             if ((errorCode = CopyOnWrite(targetptr, volptr)))
6875             {
6876                 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6877                 volptr->partition->flags &= ~PART_DONTUPDATE;
6878                 return (errorCode);
6879             }
6880             volptr->partition->flags &= ~PART_DONTUPDATE;
6881             VSetPartitionDiskUsage(volptr->partition);
6882             fdP = IH_OPEN(targetptr->handle);
6883             if (fdP == NULL)  {
6884                 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
6885                 return ENOENT;
6886             }
6887         }
6888         tinode = VN_GET_INO(targetptr);
6889     }
6890     assert(VALID_INO(tinode));
6891
6892     /* compute new file length */
6893     NewLength = DataLength;
6894     if (FileLength < NewLength)
6895         /* simulate truncate */
6896         NewLength = FileLength; 
6897     TruncatedLength = NewLength; /* remember length after possible ftruncate */
6898     if (Pos + Length > NewLength)
6899         NewLength = Pos+Length;   /* and write */
6900
6901     /* adjust the disk block count by the difference in the files */
6902     adjustSize = (int) (nBlocks(NewLength) - nBlocks(targetptr->disk.length));
6903     if((errorCode = AdjustDiskUsage(volptr, adjustSize,
6904                                    adjustSize - SpareComp(volptr)))) {
6905         FDH_CLOSE(fdP);
6906         return(errorCode);
6907     }
6908
6909     /* can signal cache manager to proceed from close now */
6910     /* this bit means that the locks are set and protections are OK */
6911     rx_SetLocalStatus(Call, 1);
6912
6913     TM_GetTimeOfDay(&StartTime, 0);
6914
6915     optSize = sendBufSize;
6916
6917     /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
6918     if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
6919     if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
6920     bytesTransfered = 0;
6921 #ifdef AFS_NT40_ENV
6922     tbuffer = AllocSendBuffer();
6923 #endif /* AFS_NT40_ENV */
6924     /* if length == 0, the loop below isn't going to do anything, including
6925      * extend the length of the inode, which it must do, since the file system
6926      * assumes that the inode length == vnode's file length.  So, we extend
6927      * the file length manually if need be.  Note that if file is bigger than
6928      * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
6929      * do what we're going to do below.
6930      */
6931     if (Length == 0 && Pos > TruncatedLength) {
6932         /* Set the file's length; we've already done an lseek to the right
6933          * spot above.
6934          */
6935         errorCode = FDH_WRITE(fdP, &tlen, 1);
6936         if (errorCode != 1) goto done;
6937         errorCode = FDH_TRUNC(fdP, Pos);
6938     }
6939     else {
6940         /* have some data to copy */
6941 #if FS_STATS_DETAILED
6942         (*a_bytesToStoreP) = Length;
6943 #endif /* FS_STATS_DETAILED */
6944         while (1) {
6945             if (bytesTransfered >= Length) {
6946                 errorCode = 0;
6947                 break;
6948             }
6949             tlen = Length -     bytesTransfered;    /* how much more to do */
6950             if (tlen > optSize) tlen = optSize; /* bound by buffer size */
6951 #ifdef AFS_NT40_ENV
6952             errorCode = rx_Read(Call, tbuffer, tlen);
6953 #else /* AFS_NT40_ENV */
6954             errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6955 #endif /* AFS_NT40_ENV */
6956 #if FS_STATS_DETAILED
6957             (*a_bytesStoredP) += errorCode;
6958 #endif /* FS_STATS_DETAILED */
6959             if (errorCode <= 0) {
6960                 errorCode = -32;
6961                 break;
6962             }
6963             tlen = errorCode;
6964 #ifdef AFS_NT40_ENV
6965             errorCode = FDH_WRITE(fdP, tbuffer, tlen);
6966 #else /* AFS_NT40_ENV */
6967             errorCode = FDH_WRITEV(fdP, tiov, tnio);
6968 #endif /* AFS_NT40_ENV */
6969             if (errorCode != tlen) {
6970                 errorCode = VDISKFULL;
6971                 break;
6972             }
6973             bytesTransfered += tlen;
6974         }
6975     }
6976   done:
6977 #ifdef AFS_NT40_ENV
6978     FreeSendBuffer((struct afs_buffer *) tbuffer);
6979 #endif /* AFS_NT40_ENV */
6980     if (sync) {
6981       FDH_SYNC(fdP);
6982     }
6983     if (errorCode) {
6984         /* something went wrong: adjust size and return */
6985         targetptr->disk.length = FDH_SIZE(fdP); /* set new file size. */
6986         /* changed_newTime is tested in StoreData to detemine if we
6987          * need to update the target vnode.
6988          */
6989         targetptr->changed_newTime = 1;
6990         FDH_CLOSE(fdP);
6991         /* set disk usage to be correct */
6992         VAdjustDiskUsage(&errorCode, volptr,
6993                          (int)(nBlocks(targetptr->disk.length)
6994                                - nBlocks(NewLength)), 0);
6995         return errorCode;
6996     }
6997     FDH_CLOSE(fdP);
6998
6999     TM_GetTimeOfDay(&StopTime, 0);
7000
7001     targetptr->disk.length = NewLength;
7002
7003     /* Update all StoreData related stats */
7004     FS_LOCK
7005     if (AFSCallStats.TotalStoredBytes > 2000000000)     /* reset if over 2 billion */
7006         AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
7007     AFSCallStats.StoreSize1++;                  /* Piggybacked data */
7008     if (targetptr->disk.length < SIZE2)
7009         AFSCallStats.StoreSize2++;
7010     else if (targetptr->disk.length < SIZE3)
7011         AFSCallStats.StoreSize3++;
7012     else if (targetptr->disk.length < SIZE4)
7013         AFSCallStats.StoreSize4++;
7014     else
7015         AFSCallStats.StoreSize5++;
7016     FS_UNLOCK
7017     return(errorCode);
7018
7019 } /*StoreData_RXStyle*/
7020
7021 static int sys2et[512];
7022
7023 void init_sys_error_to_et(void) {
7024     memset(&sys2et, 0, sizeof(sys2et));
7025     sys2et[EPERM] = UAEPERM;
7026     sys2et[ENOENT] = UAENOENT;
7027     sys2et[ESRCH] = UAESRCH;
7028     sys2et[EINTR] = UAEINTR;
7029     sys2et[EIO] = UAEIO;
7030     sys2et[ENXIO] = UAENXIO;
7031     sys2et[E2BIG] = UAE2BIG;
7032     sys2et[ENOEXEC] = UAENOEXEC;
7033     sys2et[EBADF] = UAEBADF;
7034     sys2et[ECHILD] = UAECHILD;
7035     sys2et[EAGAIN] = UAEAGAIN;
7036     sys2et[ENOMEM] = UAENOMEM;
7037     sys2et[EACCES] = UAEACCES;
7038     sys2et[EFAULT] = UAEFAULT;
7039     sys2et[ENOTBLK] = UAENOTBLK;
7040     sys2et[EBUSY] = UAEBUSY;
7041     sys2et[EEXIST] = UAEEXIST;
7042     sys2et[EXDEV] = UAEXDEV;
7043     sys2et[ENODEV] = UAENODEV;
7044     sys2et[ENOTDIR] = UAENOTDIR;
7045     sys2et[EISDIR] = UAEISDIR;
7046     sys2et[EINVAL] = UAEINVAL;
7047     sys2et[ENFILE] = UAENFILE;
7048     sys2et[EMFILE] = UAEMFILE;
7049     sys2et[ENOTTY] = UAENOTTY;
7050     sys2et[ETXTBSY] = UAETXTBSY;
7051     sys2et[EFBIG] = UAEFBIG;
7052     sys2et[ENOSPC] = UAENOSPC;
7053     sys2et[ESPIPE] = UAESPIPE;
7054     sys2et[EROFS] = UAEROFS;
7055     sys2et[EMLINK] = UAEMLINK;
7056     sys2et[EPIPE] = UAEPIPE;
7057     sys2et[EDOM] = UAEDOM;
7058     sys2et[ERANGE] = UAERANGE;
7059     sys2et[EDEADLK] = UAEDEADLK;
7060     sys2et[ENAMETOOLONG] = UAENAMETOOLONG;
7061     sys2et[ENOLCK] = UAENOLCK;
7062     sys2et[ENOSYS] = UAENOSYS;
7063     sys2et[ENOTEMPTY] = UAENOTEMPTY;
7064     sys2et[ELOOP] = UAELOOP;
7065     sys2et[EWOULDBLOCK] = UAEWOULDBLOCK;
7066     sys2et[ENOMSG] = UAENOMSG;
7067     sys2et[EIDRM] = UAEIDRM;
7068     sys2et[ECHRNG] = UAECHRNG;
7069     sys2et[EL2NSYNC] = UAEL2NSYNC;
7070     sys2et[EL3HLT] = UAEL3HLT;
7071     sys2et[EL3RST] = UAEL3RST;
7072     sys2et[ELNRNG] = UAELNRNG;
7073     sys2et[EUNATCH] = UAEUNATCH;
7074     sys2et[ENOCSI] = UAENOCSI;
7075     sys2et[EL2HLT] = UAEL2HLT;
7076     sys2et[EBADE] = UAEBADE;
7077     sys2et[EBADR] = UAEBADR;
7078     sys2et[EXFULL] = UAEXFULL;
7079     sys2et[ENOANO] = UAENOANO;
7080     sys2et[EBADRQC] = UAEBADRQC;
7081     sys2et[EBADSLT] = UAEBADSLT;
7082     sys2et[EDEADLK] = UAEDEADLK;
7083     sys2et[EBFONT] = UAEBFONT;
7084     sys2et[ENOSTR] = UAENOSTR;
7085     sys2et[ENODATA] = UAENODATA;
7086     sys2et[ETIME] = UAETIME;
7087     sys2et[ENOSR] = UAENOSR;
7088     sys2et[ENONET] = UAENONET;
7089     sys2et[ENOPKG] = UAENOPKG;
7090     sys2et[EREMOTE] = UAEREMOTE;
7091     sys2et[ENOLINK] = UAENOLINK;
7092     sys2et[EADV] = UAEADV;
7093     sys2et[ESRMNT] = UAESRMNT;
7094     sys2et[ECOMM] = UAECOMM;
7095     sys2et[EPROTO] = UAEPROTO;
7096     sys2et[EMULTIHOP] = UAEMULTIHOP;
7097     sys2et[EDOTDOT] = UAEDOTDOT;
7098     sys2et[EBADMSG] = UAEBADMSG;
7099     sys2et[EOVERFLOW] = UAEOVERFLOW;
7100     sys2et[ENOTUNIQ] = UAENOTUNIQ;
7101     sys2et[EBADFD] = UAEBADFD;
7102     sys2et[EREMCHG] = UAEREMCHG;
7103     sys2et[ELIBACC] = UAELIBACC;
7104     sys2et[ELIBBAD] = UAELIBBAD;
7105     sys2et[ELIBSCN] = UAELIBSCN;
7106     sys2et[ELIBMAX] = UAELIBMAX;
7107     sys2et[ELIBEXEC] = UAELIBEXEC;
7108     sys2et[EILSEQ] = UAEILSEQ;
7109     sys2et[ERESTART] = UAERESTART;
7110     sys2et[ESTRPIPE] = UAESTRPIPE;
7111     sys2et[EUSERS] = UAEUSERS;
7112     sys2et[ENOTSOCK] = UAENOTSOCK;
7113     sys2et[EDESTADDRREQ] = UAEDESTADDRREQ;
7114     sys2et[EMSGSIZE] = UAEMSGSIZE;
7115     sys2et[EPROTOTYPE] = UAEPROTOTYPE;
7116     sys2et[ENOPROTOOPT] = UAENOPROTOOPT;
7117     sys2et[EPROTONOSUPPORT] = UAEPROTONOSUPPORT;
7118     sys2et[ESOCKTNOSUPPORT] = UAESOCKTNOSUPPORT;
7119     sys2et[EOPNOTSUPP] = UAEOPNOTSUPP;
7120     sys2et[EPFNOSUPPORT] = UAEPFNOSUPPORT;
7121     sys2et[EAFNOSUPPORT] = UAEAFNOSUPPORT;
7122     sys2et[EADDRINUSE] = UAEADDRINUSE;
7123     sys2et[EADDRNOTAVAIL] = UAEADDRNOTAVAIL;
7124     sys2et[ENETDOWN] = UAENETDOWN;
7125     sys2et[ENETUNREACH] = UAENETUNREACH;
7126     sys2et[ENETRESET] = UAENETRESET;
7127     sys2et[ECONNABORTED] = UAECONNABORTED;
7128     sys2et[ECONNRESET] = UAECONNRESET;
7129     sys2et[ENOBUFS] = UAENOBUFS;
7130     sys2et[EISCONN] = UAEISCONN;
7131     sys2et[ENOTCONN] = UAENOTCONN;
7132     sys2et[ESHUTDOWN] = UAESHUTDOWN;
7133     sys2et[ETOOMANYREFS] = UAETOOMANYREFS;
7134     sys2et[ETIMEDOUT] = UAETIMEDOUT;
7135     sys2et[ECONNREFUSED] = UAECONNREFUSED;
7136     sys2et[EHOSTDOWN] = UAEHOSTDOWN;
7137     sys2et[EHOSTUNREACH] = UAEHOSTUNREACH;
7138     sys2et[EALREADY] = UAEALREADY;
7139     sys2et[EINPROGRESS] = UAEINPROGRESS;
7140     sys2et[ESTALE] = UAESTALE;
7141     sys2et[EUCLEAN] = UAEUCLEAN;
7142     sys2et[ENOTNAM] = UAENOTNAM;
7143     sys2et[ENAVAIL] = UAENAVAIL;
7144     sys2et[EISNAM] = UAEISNAM;
7145     sys2et[EREMOTEIO] = UAEREMOTEIO;
7146     sys2et[EDQUOT] = UAEDQUOT;
7147     sys2et[ENOMEDIUM] = UAENOMEDIUM;
7148     sys2et[EMEDIUMTYPE] = UAEMEDIUMTYPE;
7149 }
7150
7151 afs_int32 sys_error_to_et(afs_int32 in) {
7152     if (in < 0 || in > 511) return in;
7153     if (sys2et[in] != 0) return sys2et[in];
7154     return in;
7155 }