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