viced-consistent-val-and-len-cleanup-20030215
[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     if (!*name) {
1846         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1847         assert(0);
1848     }
1849     strcpy(*name, V_name(volptr));
1850     temp = strlen(V_offlineMessage(volptr)) + 1;
1851     *offMsg = malloc(temp);
1852     if (!*offMsg) {
1853         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1854         assert(0);
1855     }
1856     strcpy(*offMsg, V_offlineMessage(volptr));
1857 #if TRANSARC_VOL_STATS
1858     *motd = malloc(1);
1859     if (!*motd) {
1860         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1861         assert(0);
1862     }
1863     strcpy(*motd, nullString);
1864 #else
1865     temp = strlen(V_motd(volptr)) + 1;
1866     *motd = malloc(temp);
1867     if (!*motd) {
1868         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1869         assert(0);
1870     }
1871     strcpy(*motd, V_motd(volptr));
1872 #endif /* FS_STATS_DETAILED */
1873
1874 } /*RXGetVolumeStatus*/
1875
1876
1877 static afs_int32
1878 FileNameOK(register char *aname)
1879 {
1880     register afs_int32 i, tc;
1881     i = strlen(aname);
1882     if (i >= 4) {
1883         /* watch for @sys on the right */
1884         if (strcmp(aname+i-4, "@sys") == 0) return 0;
1885     }
1886     while ((tc = *aname++)) {
1887         if (tc == '/') return 0;    /* very bad character to encounter */
1888     }
1889     return 1;   /* file name is ok */
1890
1891 } /*FileNameOK*/
1892
1893
1894 /* Debugging tool to print Volume Statu's contents */
1895 static void
1896 PrintVolumeStatus(VolumeStatus *status)
1897 {
1898     ViceLog(5,("Volume header contains:\n"));
1899     ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1900             status->Vid, status->ParentId, status->Online, status->InService,
1901             status->Blessed, status->NeedsSalvage));
1902     ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1903     ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1904             status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1905
1906 } /*PrintVolumeStatus*/
1907
1908
1909 /*
1910  * This variant of symlink is expressly to support the AFS/DFS translator
1911  * and is not supported by the AFS fileserver. We just return EINVAL.
1912  * The cache manager should not generate this call to an AFS cache manager.
1913  */
1914 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1915                              struct AFSFid *DirFid,
1916                              char *Name,
1917                              char *LinkContents,
1918                              struct AFSStoreStatus *InStatus,
1919                              struct AFSFid *OutFid,
1920                              struct AFSFetchStatus *OutFidStatus,
1921                              struct AFSFetchStatus *OutDirStatus,
1922                              struct AFSCallBack *CallBack,
1923                              struct AFSVolSync *Sync)
1924 {
1925     return EINVAL;
1926 }
1927
1928 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1929                                struct ResidencyCmdInputs *Inputs,
1930                                struct ResidencyCmdOutputs *Outputs)
1931 {
1932     return EINVAL;
1933 }
1934
1935 static struct afs_buffer {
1936     struct afs_buffer *next;
1937 } *freeBufferList = 0;
1938 static int afs_buffersAlloced = 0;
1939
1940 static FreeSendBuffer(register struct afs_buffer *adata)
1941 {
1942     FS_LOCK
1943     afs_buffersAlloced--;
1944     adata->next = freeBufferList;
1945     freeBufferList = adata;
1946     FS_UNLOCK
1947     return 0;
1948
1949 } /*FreeSendBuffer*/
1950
1951 /* allocate space for sender */
1952 static char *AllocSendBuffer()
1953 {
1954     register struct afs_buffer *tp;
1955
1956     FS_LOCK
1957     afs_buffersAlloced++;
1958     if (!freeBufferList) {
1959         char *tmp;
1960         FS_UNLOCK
1961
1962         tmp = malloc(sendBufSize);
1963         if (!tmp) {
1964             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1965             assert(0);
1966         }
1967         return tmp;
1968     }
1969     tp = freeBufferList;
1970     freeBufferList = tp->next;
1971     FS_UNLOCK
1972     return (char *) tp;
1973
1974 } /*AllocSendBuffer*/
1975
1976 /*
1977  * This routine returns the status info associated with the targetptr vnode
1978  * in the AFSFetchStatus structure.  Some of the newer fields, such as
1979  * SegSize and Group are not yet implemented
1980  */
1981 static 
1982 void GetStatus(Vnode *targetptr,
1983                AFSFetchStatus *status,
1984                afs_int32 rights,
1985                afs_int32 anyrights,
1986                Vnode *parentptr)
1987 {
1988     /* initialize return status from a vnode  */
1989     status->InterfaceVersion = 1;
1990     status->SyncCounter = status->dataVersionHigh = status->lockCount =
1991     status->errorCode = 0;
1992     status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1993     if (targetptr->disk.type == vFile)
1994         status->FileType = File;
1995     else if (targetptr->disk.type == vDirectory)
1996         status->FileType = Directory;
1997     else if (targetptr->disk.type == vSymlink)
1998         status->FileType = SymbolicLink;
1999     else
2000         status->FileType = Invalid;                     /*invalid type field */
2001     status->LinkCount = targetptr->disk.linkCount;
2002     SET_STATUS_LEN(status, targetptr);
2003     status->DataVersion = targetptr->disk.dataVersion;
2004     status->Author = targetptr->disk.author;
2005     status->Owner = targetptr->disk.owner;
2006     status->CallerAccess = rights;
2007     status->AnonymousAccess = anyrights;
2008     status->UnixModeBits = targetptr->disk.modeBits;
2009     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2010     status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2011     status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2012     status->ServerModTime = targetptr->disk.serverModifyTime;                   
2013     status->Group = targetptr->disk.group;
2014     status->lockCount = targetptr->disk.lock.lockCount;
2015     status->errorCode = 0;
2016
2017 } /*GetStatus*/
2018
2019 static
2020 afs_int32 common_FetchData64 (struct rx_call *acall, 
2021                               struct AFSFid *Fid,    
2022                               afs_size_t Pos,         
2023                               afs_size_t Len,         
2024                               struct AFSFetchStatus *OutStatus,
2025                               struct AFSCallBack *CallBack,
2026                               struct AFSVolSync *Sync,
2027                               int type)              
2028
2029     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
2030     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
2031     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
2032     int     errorCode = 0;                  /* return code to caller */
2033     int     fileCode =  0;                  /* return code from vol package */
2034     Volume * volptr = 0;                    /* pointer to the volume */
2035     struct client *client;                  /* pointer to the client data */
2036     struct rx_connection *tcon;             /* the connection we're part of */
2037     afs_int32 rights, anyrights;                    /* rights for this and any user */
2038     struct client *t_client;                /* tmp ptr to client data */
2039     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2040 #if FS_STATS_DETAILED
2041     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2042     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2043     struct timeval opStartTime,
2044                    opStopTime;              /* Start/stop times for RPC op*/
2045     struct timeval xferStartTime,
2046                    xferStopTime;            /* Start/stop times for xfer portion*/
2047     struct timeval elapsedTime;             /* Transfer time */
2048     afs_size_t bytesToXfer;                         /* # bytes to xfer*/
2049     afs_size_t bytesXferred;                        /* # bytes actually xferred*/
2050     int readIdx;                            /* Index of read stats array to bump*/
2051     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2052
2053     /*
2054      * Set our stats pointers, remember when the RPC operation started, and
2055      * tally the operation.
2056      */
2057     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2058     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2059     FS_LOCK
2060     (opP->numOps)++;
2061     FS_UNLOCK
2062     TM_GetTimeOfDay(&opStartTime, 0);
2063 #endif /* FS_STATS_DETAILED */
2064
2065     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2066             Fid->Volume, Fid->Vnode, Fid->Unique));     
2067     FS_LOCK
2068     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2069     FS_UNLOCK
2070
2071     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2072         goto Bad_FetchData;
2073
2074     /* Get ptr to client data for user Id for logging */
2075     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2076     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2077     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2078             Fid->Volume, Fid->Vnode, Fid->Unique,
2079             inet_ntoa(logHostAddr), t_client->ViceId)); 
2080     /*
2081      * Get volume/vnode for the fetched file; caller's access rights to
2082      * it are also returned
2083      */
2084     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2085                                      DONTCHECK, &parentwhentargetnotdir,
2086                                      &client, READ_LOCK, &rights, &anyrights)))
2087         goto Bad_FetchData;
2088
2089     SetVolumeSync(Sync, volptr);
2090
2091 #if FS_STATS_DETAILED
2092     /*
2093      * Remember that another read operation was performed.
2094      */
2095     FS_LOCK
2096     if (client->InSameNetwork)
2097         readIdx = VOL_STATS_SAME_NET;
2098     else
2099         readIdx = VOL_STATS_DIFF_NET;
2100     V_stat_reads(volptr, readIdx)++;
2101     if (client->ViceId != AnonymousID) {
2102         V_stat_reads(volptr, readIdx+1)++;
2103     }
2104     FS_UNLOCK
2105 #endif /* FS_STATS_DETAILED */
2106
2107     /* Check whether the caller has permission access to fetch the data */
2108     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2109                                            CHK_FETCHDATA, 0))) 
2110         goto Bad_FetchData;
2111
2112     /*
2113      * Drop the read lock on the parent directory after saving the parent
2114      * vnode information we need to pass to GetStatus
2115      */
2116     if (parentwhentargetnotdir != NULL) {
2117         tparentwhentargetnotdir = *parentwhentargetnotdir;
2118         VPutVnode(&fileCode, parentwhentargetnotdir);
2119         assert(!fileCode || (fileCode == VSALVAGE));
2120         parentwhentargetnotdir = NULL;
2121     }
2122
2123 #if FS_STATS_DETAILED
2124     /*
2125      * Remember when the data transfer started.
2126      */
2127     TM_GetTimeOfDay(&xferStartTime, 0);
2128 #endif /* FS_STATS_DETAILED */
2129
2130     /* actually do the data transfer */
2131 #if FS_STATS_DETAILED
2132     errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2133                                   (afs_size_t) Pos, (afs_size_t) Len, type,
2134                                   &bytesToXfer, &bytesXferred);
2135 #else
2136     if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2137                                        (afs_size_t) Pos, (afs_size_t) Len,
2138                                        type)))
2139         goto Bad_FetchData;
2140 #endif /* FS_STATS_DETAILED */
2141
2142 #if FS_STATS_DETAILED
2143     /*
2144      * At this point, the data transfer is done, for good or ill.  Remember
2145      * when the transfer ended, bump the number of successes/failures, and
2146      * integrate the transfer size and elapsed time into the stats.  If the
2147      * operation failed, we jump to the appropriate point.
2148      */
2149     TM_GetTimeOfDay(&xferStopTime, 0);
2150     FS_LOCK
2151     (xferP->numXfers)++;
2152     if (!errorCode) {
2153         (xferP->numSuccesses)++;
2154
2155         /*
2156          * Bump the xfer sum by the number of bytes actually sent, NOT the
2157          * target number.
2158          */
2159         tot_bytesXferred += bytesXferred;
2160         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2161         tot_bytesXferred &= 0x3FF;
2162         if (bytesXferred < xferP->minBytes)
2163             xferP->minBytes = bytesXferred;
2164         if (bytesXferred > xferP->maxBytes)
2165             xferP->maxBytes = bytesXferred;
2166
2167         /*
2168          * Tally the size of the object.  Note: we tally the actual size,
2169          * NOT the number of bytes that made it out over the wire.
2170          */
2171         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2172             (xferP->count[0])++;
2173         else
2174             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2175                 (xferP->count[1])++;
2176         else
2177             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2178                 (xferP->count[2])++;
2179         else
2180             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2181                 (xferP->count[3])++;
2182         else
2183             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2184                 (xferP->count[4])++;
2185         else
2186             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2187                 (xferP->count[5])++;
2188         else
2189             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2190                 (xferP->count[6])++;
2191         else
2192             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2193                 (xferP->count[7])++;
2194         else
2195             (xferP->count[8])++;
2196
2197         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2198         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2199         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2200         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2201             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2202         }
2203         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2204             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2205         }
2206       }
2207     FS_UNLOCK
2208     /*
2209      * Finally, go off to tell our caller the bad news in case the
2210      * fetch failed.
2211      */
2212     if (errorCode)
2213         goto Bad_FetchData;
2214 #endif /* FS_STATS_DETAILED */
2215
2216     /* write back  the OutStatus from the target vnode  */
2217     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2218
2219     /* if a r/w volume, promise a callback to the caller */
2220     if (VolumeWriteable(volptr))
2221         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2222     else {
2223       struct AFSFid myFid;              
2224       memset(&myFid, 0, sizeof(struct AFSFid));
2225       myFid.Volume = Fid->Volume;
2226       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2227       }
2228
2229 Bad_FetchData: 
2230     /* Update and store volume/vnode and parent vnodes back */
2231     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2232     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
2233     CallPostamble(tcon);
2234
2235 #if FS_STATS_DETAILED
2236     TM_GetTimeOfDay(&opStopTime, 0);
2237     if (errorCode == 0) {
2238         FS_LOCK
2239         (opP->numSuccesses)++;
2240         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2241         fs_stats_AddTo((opP->sumTime), elapsedTime);
2242         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2243         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2244             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2245         }
2246         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2247             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2248         }
2249         FS_UNLOCK
2250       }
2251
2252 #endif /* FS_STATS_DETAILED */
2253
2254     osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2255     return(errorCode);
2256
2257 } /*common_FetchData64*/
2258
2259 afs_int32 SRXAFS_FetchData (struct rx_call *acall,   
2260                             struct AFSFid *Fid,      
2261                             afs_int32 Pos,           
2262                             afs_int32 Len,           
2263                             struct AFSFetchStatus *OutStatus,
2264                             struct AFSCallBack *CallBack, 
2265                             struct AFSVolSync *Sync) 
2266
2267 {
2268     int code;
2269
2270     code = common_FetchData64 (acall, Fid,
2271                                (afs_size_t) Pos, (afs_size_t) Len,
2272                                OutStatus,
2273                                CallBack, Sync, 0);
2274     return code;
2275 }
2276
2277 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall, 
2278                               struct AFSFid *Fid,    
2279                               afs_int64 Pos,         
2280                               afs_int64 Len,         
2281                               struct AFSFetchStatus *OutStatus,
2282                               struct AFSCallBack *CallBack,
2283                               struct AFSVolSync *Sync)
2284 {
2285     int code;
2286     afs_size_t tPos, tLen;
2287
2288 #ifdef AFS_64BIT_ENV
2289 #ifndef AFS_LARGEFILE_ENV
2290     if (Pos + Len > 0x7fffffff)
2291         return E2BIG;
2292 #endif  /* !AFS_LARGEFILE_ENV */
2293     tPos = Pos;
2294     tLen = Len;
2295 #else /* AFS_64BIT_ENV */
2296     if (Pos.high || Len.high)
2297         return E2BIG;
2298     tPos = Pos.low;
2299     tLen = Len.low;
2300 #endif /* AFS_64BIT_ENV */
2301
2302     code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2303                              CallBack, Sync, 1);
2304     return code;
2305 }
2306
2307 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,    
2308                            struct AFSFid *Fid,       
2309                            struct AFSOpaque *AccessList,     
2310                            struct AFSFetchStatus *OutStatus, 
2311                            struct AFSVolSync *Sync)
2312 {
2313     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2314     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2315     int     errorCode = 0;              /* return error code to caller */
2316     Volume * volptr = 0;                /* pointer to the volume */
2317     struct client *client;              /* pointer to the client data */
2318     afs_int32 rights, anyrights;                /* rights for this and any user */
2319     struct rx_connection *tcon = rx_ConnectionOf(acall);
2320     struct client *t_client;                /* tmp ptr to client data */
2321     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2322 #if FS_STATS_DETAILED
2323     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2324     struct timeval opStartTime,
2325                    opStopTime;              /* Start/stop times for RPC op*/
2326     struct timeval elapsedTime;             /* Transfer time */
2327
2328     /*
2329      * Set our stats pointer, remember when the RPC operation started, and
2330      * tally the operation.
2331      */
2332     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2333     FS_LOCK
2334     (opP->numOps)++;
2335     FS_UNLOCK
2336     TM_GetTimeOfDay(&opStartTime, 0);
2337 #endif /* FS_STATS_DETAILED */
2338
2339     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2340             Fid->Volume, Fid->Vnode, Fid->Unique));
2341     FS_LOCK
2342     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2343     FS_UNLOCK
2344     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2345         goto Bad_FetchACL;
2346
2347     /* Get ptr to client data for user Id for logging */
2348     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2349     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2350     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2351             Fid->Volume, Fid->Vnode, Fid->Unique,
2352             inet_ntoa(logHostAddr), t_client->ViceId));
2353
2354     AccessList->AFSOpaque_len = 0;
2355     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2356     if (!AccessList->AFSOpaque_val) {
2357         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2358         assert(0);
2359     }
2360
2361     /*
2362      * Get volume/vnode for the fetched file; caller's access rights to it
2363      * are also returned
2364      */
2365     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2366                                      DONTCHECK, &parentwhentargetnotdir,
2367                                      &client, READ_LOCK, &rights, &anyrights)))
2368         goto Bad_FetchACL;
2369
2370     SetVolumeSync(Sync, volptr);
2371
2372     /* Check whether we have permission to fetch the ACL */
2373     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2374                                            CHK_FETCHACL, 0)))
2375         goto Bad_FetchACL;
2376
2377     /* Get the Access List from the dir's vnode */
2378     if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2379                                        AccessList)))
2380         goto Bad_FetchACL;
2381
2382     /* Get OutStatus back From the target Vnode  */
2383     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2384
2385 Bad_FetchACL: 
2386     /* Update and store volume/vnode and parent vnodes back */
2387     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2388     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2389             errorCode, AccessList->AFSOpaque_val));
2390     CallPostamble(tcon);
2391
2392 #if FS_STATS_DETAILED
2393     TM_GetTimeOfDay(&opStopTime, 0);
2394     if (errorCode == 0) {
2395         FS_LOCK
2396         (opP->numSuccesses)++;
2397         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2398         fs_stats_AddTo((opP->sumTime), elapsedTime);
2399         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2400         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2401             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2402         }
2403         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2404             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2405         }
2406         FS_UNLOCK
2407       }
2408
2409 #endif /* FS_STATS_DETAILED */
2410
2411     osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2412     return errorCode;
2413 } /*SRXAFS_FetchACL*/
2414
2415
2416 /*
2417  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2418  * merged into it when possible.
2419  */
2420 static 
2421 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2422                              struct AFSFid *Fid,  
2423                              struct AFSFetchStatus *OutStatus,
2424                              struct AFSCallBack *CallBack,      
2425                              struct AFSVolSync *Sync)           
2426 {
2427     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2428     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2429     int     errorCode = 0;              /* return code to caller */
2430     Volume * volptr = 0;                /* pointer to the volume */
2431     struct client *client;              /* pointer to the client data */
2432     afs_int32 rights, anyrights;                /* rights for this and any user */
2433     struct client *t_client;            /* tmp ptr to client data */
2434     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2435     struct rx_connection *tcon = rx_ConnectionOf(acall);
2436
2437     /* Get ptr to client data for user Id for logging */
2438     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2439     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2440     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
2441             Fid->Volume, Fid->Vnode, Fid->Unique,
2442             inet_ntoa(logHostAddr), t_client->ViceId));
2443     FS_LOCK
2444     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2445     FS_UNLOCK
2446     /*
2447      * Get volume/vnode for the fetched file; caller's rights to it are
2448      * also returned
2449      */
2450     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2451                                      DONTCHECK, &parentwhentargetnotdir,
2452                                      &client, READ_LOCK, &rights, &anyrights)))
2453         goto Bad_FetchStatus;
2454
2455     /* set volume synchronization information */
2456     SetVolumeSync(Sync, volptr);
2457
2458     /* Are we allowed to fetch Fid's status? */
2459     if (targetptr->disk.type != vDirectory) {
2460       if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2461                                              CHK_FETCHSTATUS, 0))) {
2462           if (rx_GetCallAbortCode(acall) == errorCode) 
2463               rx_SetCallAbortCode(acall, 0);
2464           goto Bad_FetchStatus;
2465       }
2466     }
2467
2468     /* set OutStatus From the Fid  */
2469     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2470
2471     /* If a r/w volume, also set the CallBack state */
2472     if (VolumeWriteable(volptr))
2473         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2474     else {
2475       struct AFSFid myFid;              
2476       memset(&myFid, 0, sizeof(struct AFSFid));
2477       myFid.Volume = Fid->Volume;
2478       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2479       }
2480
2481 Bad_FetchStatus: 
2482     /* Update and store volume/vnode and parent vnodes back */
2483     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2484     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
2485     return errorCode;
2486
2487 } /*SAFSS_FetchStatus*/
2488
2489
2490 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2491                             struct AFSCBFids *Fids,
2492                             struct AFSBulkStats *OutStats,
2493                             struct AFSCBs *CallBacks,
2494                             struct AFSVolSync *Sync)
2495 {
2496     register int i;
2497     afs_int32 nfiles;
2498     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2499     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2500     int     errorCode = 0;              /* return code to caller */
2501     Volume * volptr = 0;                /* pointer to the volume */
2502     struct client *client;              /* pointer to the client data */
2503     afs_int32 rights, anyrights;                /* rights for this and any user */
2504     register struct AFSFid *tfid;       /* file id we're dealing with now */
2505     struct rx_connection *tcon = rx_ConnectionOf(acall);
2506 #if FS_STATS_DETAILED
2507     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2508     struct timeval opStartTime,
2509                    opStopTime;              /* Start/stop times for RPC op*/
2510     struct timeval elapsedTime;             /* Transfer time */
2511
2512     /*
2513      * Set our stats pointer, remember when the RPC operation started, and
2514      * tally the operation.
2515      */
2516     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2517     FS_LOCK
2518     (opP->numOps)++;
2519     FS_UNLOCK
2520     TM_GetTimeOfDay(&opStartTime, 0);
2521 #endif /* FS_STATS_DETAILED */
2522
2523     ViceLog(1, ("SAFS_BulkStatus\n"));
2524     FS_LOCK
2525     AFSCallStats.TotalCalls++;
2526     FS_UNLOCK
2527
2528     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2529     if (nfiles <= 0) {                  /* Sanity check */
2530         errorCode = EINVAL;
2531         goto Audit_and_Return;
2532     }
2533
2534     /* allocate space for return output parameters */
2535     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2536         malloc(nfiles * sizeof(struct AFSFetchStatus));
2537     if (!OutStats->AFSBulkStats_val) {
2538         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2539         assert(0);
2540     }
2541     OutStats->AFSBulkStats_len = nfiles;
2542     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2543         malloc(nfiles * sizeof(struct AFSCallBack));
2544     if (!CallBacks->AFSCBs_val) {
2545         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2546         assert(0);
2547     }
2548     CallBacks->AFSCBs_len = nfiles;
2549
2550     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2551         goto Bad_BulkStatus;
2552
2553     tfid = Fids->AFSCBFids_val;
2554     for (i=0; i<nfiles; i++, tfid++) {
2555         /*
2556          * Get volume/vnode for the fetched file; caller's rights to it
2557          * are also returned
2558          */
2559         if ((errorCode =
2560             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2561                              DONTCHECK, &parentwhentargetnotdir, &client,
2562                              READ_LOCK, &rights, &anyrights)))
2563                 goto Bad_BulkStatus;
2564         /* set volume synchronization information, but only once per call */
2565         if (i == nfiles)
2566             SetVolumeSync(Sync, volptr);
2567
2568         /* Are we allowed to fetch Fid's status? */
2569         if (targetptr->disk.type != vDirectory) {
2570             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2571                                                    CHK_FETCHSTATUS, 0))) {
2572                 if (rx_GetCallAbortCode(acall) == errorCode) 
2573                     rx_SetCallAbortCode(acall, 0);
2574                 goto Bad_BulkStatus;
2575             }
2576         }
2577
2578         /* set OutStatus From the Fid  */
2579         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2580                   rights, anyrights, parentwhentargetnotdir);
2581
2582         /* If a r/w volume, also set the CallBack state */
2583         if (VolumeWriteable(volptr))
2584             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2585                               &CallBacks->AFSCBs_val[i]);
2586         else {
2587           struct AFSFid myFid;          
2588           memset(&myFid, 0, sizeof(struct AFSFid));
2589           myFid.Volume = tfid->Volume;
2590           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2591                               &CallBacks->AFSCBs_val[i]);
2592         }
2593
2594         /* put back the file ID and volume */
2595         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2596         parentwhentargetnotdir = (Vnode *) 0;
2597         targetptr = (Vnode *) 0;
2598         volptr = (Volume *) 0;
2599     }
2600
2601 Bad_BulkStatus: 
2602     /* Update and store volume/vnode and parent vnodes back */
2603     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2604     CallPostamble(tcon);
2605
2606 #if FS_STATS_DETAILED
2607     TM_GetTimeOfDay(&opStopTime, 0);
2608     if (errorCode == 0) {
2609         FS_LOCK
2610         (opP->numSuccesses)++;
2611         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2612         fs_stats_AddTo((opP->sumTime), elapsedTime);
2613         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2614         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2615             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2616         }
2617         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2618             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2619         }
2620         FS_UNLOCK
2621     }   
2622
2623 #endif /* FS_STATS_DETAILED */
2624
2625 Audit_and_Return:
2626     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
2627     osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2628     return errorCode;
2629
2630 } /*SRXAFS_BulkStatus*/
2631
2632
2633 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2634                                   struct AFSCBFids *Fids,
2635                                   struct AFSBulkStats *OutStats,
2636                                   struct AFSCBs *CallBacks,
2637                                   struct AFSVolSync *Sync)
2638 {
2639     register int i;
2640     afs_int32 nfiles;
2641     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2642     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2643     int     errorCode = 0;              /* return code to caller */
2644     Volume * volptr = 0;                /* pointer to the volume */
2645     struct client *client;              /* pointer to the client data */
2646     afs_int32 rights, anyrights;                /* rights for this and any user */
2647     register struct AFSFid *tfid;       /* file id we're dealing with now */
2648     struct rx_connection *tcon;
2649     AFSFetchStatus *tstatus;
2650 #if FS_STATS_DETAILED
2651     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2652     struct timeval opStartTime,
2653                    opStopTime;              /* Start/stop times for RPC op*/
2654     struct timeval elapsedTime;             /* Transfer time */
2655
2656     /*
2657      * Set our stats pointer, remember when the RPC operation started, and
2658      * tally the operation.
2659      */
2660     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2661     FS_LOCK
2662     (opP->numOps)++;
2663     FS_UNLOCK
2664     TM_GetTimeOfDay(&opStartTime, 0);
2665 #endif /* FS_STATS_DETAILED */
2666
2667     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2668     FS_LOCK
2669     AFSCallStats.TotalCalls++;
2670     FS_UNLOCK
2671
2672     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2673     if (nfiles <= 0) {                  /* Sanity check */
2674         errorCode = EINVAL;
2675         goto Audit_and_Return;
2676     }
2677
2678     /* allocate space for return output parameters */
2679     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2680         malloc(nfiles * sizeof(struct AFSFetchStatus));
2681     if (!OutStats->AFSBulkStats_val) {
2682         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2683         assert(0);
2684     }
2685     OutStats->AFSBulkStats_len = nfiles;
2686     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2687         malloc(nfiles * sizeof(struct AFSCallBack));
2688     if (!CallBacks->AFSCBs_val) {
2689         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2690         assert(0);
2691     }
2692     CallBacks->AFSCBs_len = nfiles;
2693
2694     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2695         goto Bad_InlineBulkStatus;
2696     }
2697
2698     tfid = Fids->AFSCBFids_val;
2699     for (i=0; i<nfiles; i++, tfid++) {
2700         /*
2701          * Get volume/vnode for the fetched file; caller's rights to it
2702          * are also returned
2703          */
2704         if ((errorCode =
2705             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2706                              DONTCHECK, &parentwhentargetnotdir, &client,
2707                              READ_LOCK, &rights, &anyrights))) {
2708             tstatus = &OutStats->AFSBulkStats_val[i];
2709             tstatus->errorCode = errorCode;
2710             parentwhentargetnotdir = (Vnode *) 0;
2711             targetptr = (Vnode *) 0;
2712             volptr = (Volume *) 0;
2713             continue;
2714         }
2715
2716         /* set volume synchronization information, but only once per call */
2717         if (i == nfiles)
2718             SetVolumeSync(Sync, volptr);
2719
2720         /* Are we allowed to fetch Fid's status? */
2721         if (targetptr->disk.type != vDirectory) {
2722             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2723                                                    CHK_FETCHSTATUS, 0))) {
2724                 tstatus = &OutStats->AFSBulkStats_val[i];
2725                 tstatus->errorCode = errorCode;
2726                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2727                 parentwhentargetnotdir = (Vnode *) 0;
2728                 targetptr = (Vnode *) 0;
2729                 volptr = (Volume *) 0;
2730                 continue;
2731             }
2732         }
2733
2734         /* set OutStatus From the Fid  */
2735         GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], 
2736           rights, anyrights, parentwhentargetnotdir);
2737
2738         /* If a r/w volume, also set the CallBack state */
2739         if (VolumeWriteable(volptr))
2740             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2741                               &CallBacks->AFSCBs_val[i]);
2742         else {
2743           struct AFSFid myFid;          
2744           memset(&myFid, 0, sizeof(struct AFSFid));
2745           myFid.Volume = tfid->Volume;
2746           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2747                               &CallBacks->AFSCBs_val[i]);
2748         }
2749
2750         /* put back the file ID and volume */
2751         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2752         parentwhentargetnotdir = (Vnode *) 0;
2753         targetptr = (Vnode *) 0;
2754         volptr = (Volume *) 0;
2755     }
2756
2757 Bad_InlineBulkStatus: 
2758     /* Update and store volume/vnode and parent vnodes back */
2759     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2760     CallPostamble(tcon);
2761
2762 #if FS_STATS_DETAILED
2763     TM_GetTimeOfDay(&opStopTime, 0);
2764     if (errorCode == 0) {
2765         FS_LOCK
2766         (opP->numSuccesses)++;
2767         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2768         fs_stats_AddTo((opP->sumTime), elapsedTime);
2769         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2770         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2771             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2772         }
2773         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2774             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2775         }
2776         FS_UNLOCK
2777     }   
2778
2779 #endif /* FS_STATS_DETAILED */
2780
2781 Audit_and_Return:
2782     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
2783     osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2784     return 0;
2785
2786 } /*SRXAFS_InlineBulkStatus*/
2787
2788
2789 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,            
2790                               struct AFSFid *Fid,               
2791                               struct AFSFetchStatus *OutStatus, 
2792                               struct AFSCallBack *CallBack,     
2793                               struct AFSVolSync *Sync)
2794 {
2795     afs_int32 code;
2796     struct rx_connection *tcon;
2797 #if FS_STATS_DETAILED
2798     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2799     struct timeval opStartTime,
2800                    opStopTime;              /* Start/stop times for RPC op*/
2801     struct timeval elapsedTime;             /* Transfer time */
2802
2803     /*
2804      * Set our stats pointer, remember when the RPC operation started, and
2805      * tally the operation.
2806      */
2807     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2808     FS_LOCK
2809     (opP->numOps)++;
2810     FS_UNLOCK
2811     TM_GetTimeOfDay(&opStartTime, 0);
2812 #endif /* FS_STATS_DETAILED */
2813
2814     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2815         goto Bad_FetchStatus;
2816
2817     code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2818
2819 Bad_FetchStatus:    
2820     CallPostamble(tcon);
2821
2822 #if FS_STATS_DETAILED
2823     TM_GetTimeOfDay(&opStopTime, 0);
2824     if (code == 0) {
2825         FS_LOCK
2826         (opP->numSuccesses)++;
2827         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2828         fs_stats_AddTo((opP->sumTime), elapsedTime);
2829         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2830         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2831             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2832         }
2833         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2834             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2835         }
2836         FS_UNLOCK
2837       }
2838
2839 #endif /* FS_STATS_DETAILED */
2840
2841     osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2842     return code;
2843
2844 } /*SRXAFS_FetchStatus*/
2845
2846 static
2847 afs_int32 common_StoreData64 (struct rx_call *acall,
2848                               struct AFSFid *Fid,               
2849                               struct AFSStoreStatus *InStatus,  
2850                               afs_offs_t Pos,                   
2851                               afs_offs_t Length,                
2852                               afs_offs_t FileLength,            
2853                               struct AFSFetchStatus *OutStatus, 
2854                               struct AFSVolSync *Sync)
2855 {
2856     Vnode * targetptr = 0;              /* pointer to input fid */
2857     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2858     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
2859     int     errorCode = 0;              /* return code for caller */
2860     int     fileCode =  0;              /* return code from vol package */
2861     Volume * volptr = 0;                /* pointer to the volume header */
2862     struct client * client;             /* pointer to client structure */
2863     afs_int32 rights, anyrights;                /* rights for this and any user */
2864     struct client *t_client;            /* tmp ptr to client data */
2865     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2866     struct rx_connection *tcon;
2867 #if FS_STATS_DETAILED
2868     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2869     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2870     struct timeval opStartTime,
2871                    opStopTime;              /* Start/stop times for RPC op*/
2872     struct timeval xferStartTime,
2873                    xferStopTime;            /* Start/stop times for xfer portion*/
2874     struct timeval elapsedTime;             /* Transfer time */
2875     afs_size_t bytesToXfer;                         /* # bytes to xfer */
2876     afs_size_t bytesXferred;                        /* # bytes actually xfer */
2877     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2878
2879     /*
2880      * Set our stats pointers, remember when the RPC operation started, and
2881      * tally the operation.
2882      */
2883     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2884     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2885     FS_LOCK
2886     (opP->numOps)++;
2887     FS_UNLOCK
2888
2889     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2890             Fid->Volume, Fid->Vnode, Fid->Unique));
2891     TM_GetTimeOfDay(&opStartTime, 0);
2892 #endif /* FS_STATS_DETAILED */
2893
2894     FS_LOCK
2895     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2896     FS_UNLOCK
2897
2898     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2899         goto Bad_StoreData;
2900
2901     /* Get ptr to client data for user Id for logging */
2902     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2903     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2904     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2905             Fid->Volume, Fid->Vnode, Fid->Unique,
2906             inet_ntoa(logHostAddr), t_client->ViceId));
2907 #ifdef AFS_LARGEFILE_ENV
2908     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",
2909                 Fid->Volume, Fid->Vnode, Fid->Unique,
2910                 inet_ntoa(logHostAddr), t_client->ViceId,
2911                 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
2912                 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff),
2913                 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff)));
2914 #else /* !AFS_LARGEFILE_ENV */
2915     ViceLog(25, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d, Pos 0X%x, Len 0X%x, FileLen 0X%x\n",
2916                 Fid->Volume, Fid->Vnode, Fid->Unique,
2917                 inet_ntoa(logHostAddr), t_client->ViceId,
2918                 Pos,
2919                 Length,
2920                 FileLength));
2921 #endif /* !AFS_LARGEFILE_ENV */
2922                 
2923
2924     /*
2925      * Get associated volume/vnode for the stored file; caller's rights
2926      * are also returned
2927      */
2928     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2929                                      MustNOTBeDIR, &parentwhentargetnotdir,
2930                                      &client, WRITE_LOCK, &rights, &anyrights))) {
2931         goto Bad_StoreData;
2932     }
2933
2934     /* set volume synchronization information */
2935     SetVolumeSync(Sync, volptr);
2936
2937     if ((targetptr->disk.type == vSymlink)) {
2938         /* Should we return a better error code here??? */
2939         errorCode = EISDIR;
2940         goto Bad_StoreData;
2941     }
2942
2943     /* Check if we're allowed to store the data */
2944     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2945                                            CHK_STOREDATA, InStatus))) {
2946         goto Bad_StoreData;
2947     }
2948
2949     /*
2950      * Drop the read lock on the parent directory after saving the parent
2951      * vnode information we need to pass to GetStatus
2952      */
2953     if (parentwhentargetnotdir != NULL) {
2954         tparentwhentargetnotdir = *parentwhentargetnotdir;
2955         VPutVnode(&fileCode, parentwhentargetnotdir);
2956         assert(!fileCode || (fileCode == VSALVAGE));
2957         parentwhentargetnotdir = NULL;
2958     }
2959
2960
2961
2962 #if FS_STATS_DETAILED
2963     /*
2964      * Remember when the data transfer started.
2965      */
2966     TM_GetTimeOfDay(&xferStartTime, 0);
2967 #endif /* FS_STATS_DETAILED */
2968
2969     /* Do the actual storing of the data */
2970 #if FS_STATS_DETAILED
2971     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2972                                   (afs_size_t) Pos, (afs_size_t) Length,
2973                                   (afs_size_t) FileLength,
2974                                   (InStatus->Mask & AFS_FSYNC),
2975                                   &bytesToXfer, &bytesXferred);
2976 #else
2977     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2978                                   acall,
2979                                   (afs_size_t) Pos, (afs_size_t) Length,
2980                                   (afs_size_t) FileLength,
2981                                   (InStatus->Mask & AFS_FSYNC));
2982     if (errorCode && (!targetptr->changed_newTime))
2983             goto Bad_StoreData;
2984 #endif /* FS_STATS_DETAILED */
2985 #if FS_STATS_DETAILED
2986     /*
2987      * At this point, the data transfer is done, for good or ill.  Remember
2988      * when the transfer ended, bump the number of successes/failures, and
2989      * integrate the transfer size and elapsed time into the stats.  If the
2990      * operation failed, we jump to the appropriate point.
2991      */
2992     TM_GetTimeOfDay(&xferStopTime, 0);
2993     FS_LOCK
2994     (xferP->numXfers)++;
2995     if (!errorCode) {
2996         (xferP->numSuccesses)++;
2997
2998         /*
2999          * Bump the xfer sum by the number of bytes actually sent, NOT the
3000          * target number.
3001          */
3002         tot_bytesXferred += bytesXferred;
3003         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3004         tot_bytesXferred &= 0x3FF;
3005         if (bytesXferred < xferP->minBytes)
3006             xferP->minBytes = bytesXferred;
3007         if (bytesXferred > xferP->maxBytes)
3008             xferP->maxBytes = bytesXferred;
3009       
3010         /*
3011          * Tally the size of the object.  Note: we tally the actual size,
3012          * NOT the number of bytes that made it out over the wire.
3013          */
3014         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3015             (xferP->count[0])++;
3016         else
3017             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3018                 (xferP->count[1])++;
3019         else
3020             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3021                 (xferP->count[2])++;
3022         else
3023             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3024                 (xferP->count[3])++;
3025         else
3026             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3027                 (xferP->count[4])++;
3028         else
3029             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3030                 (xferP->count[5])++;
3031         else
3032             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3033                 (xferP->count[6])++;
3034         else
3035             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3036                 (xferP->count[7])++;
3037         else
3038             (xferP->count[8])++;
3039       
3040         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3041         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3042         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3043         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3044             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3045         }
3046         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3047             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3048         }
3049     }
3050     FS_UNLOCK
3051
3052     /*
3053      * Finally, go off to tell our caller the bad news in case the
3054      * store failed.
3055      */
3056     if (errorCode && (!targetptr->changed_newTime))
3057             goto Bad_StoreData;
3058 #endif /* FS_STATS_DETAILED */
3059
3060     /* Update the status of the target's vnode */
3061     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
3062                              volptr, (afs_size_t) 0);
3063
3064     /* Get the updated File's status back to the caller */
3065     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
3066
3067 Bad_StoreData: 
3068     /* Update and store volume/vnode and parent vnodes back */
3069     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3070     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3071
3072     CallPostamble(tcon);
3073
3074 #if FS_STATS_DETAILED
3075     TM_GetTimeOfDay(&opStopTime, 0);
3076     if (errorCode == 0) {
3077         FS_LOCK
3078         (opP->numSuccesses)++;
3079         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3080         fs_stats_AddTo((opP->sumTime), elapsedTime);
3081         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3082         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3083             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3084         }
3085         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3086             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3087         }
3088         FS_UNLOCK
3089       }
3090 #endif /* FS_STATS_DETAILED */
3091
3092     osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
3093     return(errorCode);
3094
3095 } /*common_StoreData64*/
3096
3097 afs_int32 SRXAFS_StoreData (struct rx_call *acall,              
3098                             struct AFSFid *Fid,                 
3099                             struct AFSStoreStatus *InStatus,    
3100                             afs_uint32 Pos,                     
3101                             afs_uint32 Length,                  
3102                             afs_uint32 FileLength,              
3103                             struct AFSFetchStatus *OutStatus,   
3104                             struct AFSVolSync *Sync)
3105 {
3106     int code;
3107
3108     code = common_StoreData64 (acall, Fid, InStatus, Pos, Length, FileLength,
3109                              OutStatus, Sync);
3110     return code;
3111
3112 } /*SRXAFS_StoreData*/
3113
3114 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,            
3115                               struct AFSFid *Fid,               
3116                               struct AFSStoreStatus *InStatus,  
3117                               afs_uint64 Pos,                   
3118                               afs_uint64 Length,                
3119                               afs_uint64 FileLength,            
3120                               struct AFSFetchStatus *OutStatus, 
3121                               struct AFSVolSync *Sync)
3122 {
3123     int code;
3124     afs_offs_t tPos;
3125     afs_offs_t tLength;
3126     afs_offs_t tFileLength;
3127
3128 #ifdef AFS_64BIT_ENV
3129 #ifndef AFS_LARGEFILE_ENV
3130     if (FileLength > 0x7fffffff)
3131         return E2BIG;
3132 #endif /* !AFS_LARGEFILE_ENV */
3133     tPos = Pos;
3134     tLength = Length;
3135     tFileLength = FileLength;
3136 #else /* AFS_64BIT_ENV */
3137     if (FileLength.high)
3138         return E2BIG;
3139     tPos = Pos.low;
3140     tLength = Length.low;
3141     tFileLength = FileLength.low;
3142 #endif /* AFS_64BIT_ENV */
3143
3144     code = common_StoreData64 (acall, Fid, InStatus, tPos, tLength, tFileLength,
3145                              OutStatus, Sync);
3146     return code;
3147 }
3148
3149 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,               
3150                            struct AFSFid *Fid,                  
3151                            struct AFSOpaque *AccessList,        
3152                            struct AFSFetchStatus *OutStatus,
3153                            struct AFSVolSync *Sync)
3154 {
3155     Vnode * targetptr = 0;              /* pointer to input fid */
3156     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3157     int     errorCode = 0;              /* return code for caller */
3158     struct AFSStoreStatus InStatus;     /* Input status for fid */
3159     Volume * volptr = 0;                /* pointer to the volume header */
3160     struct client * client;             /* pointer to client structure */
3161     afs_int32 rights, anyrights;                /* rights for this and any user */
3162     struct rx_connection *tcon;
3163     struct client *t_client;            /* tmp ptr to client data */
3164     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
3165 #if FS_STATS_DETAILED
3166     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3167     struct timeval opStartTime,
3168                    opStopTime;              /* Start/stop times for RPC op*/
3169     struct timeval elapsedTime;             /* Transfer time */
3170
3171     /*
3172      * Set our stats pointer, remember when the RPC operation started, and
3173      * tally the operation.
3174      */
3175     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3176     FS_LOCK
3177     (opP->numOps)++;
3178     FS_UNLOCK
3179     TM_GetTimeOfDay(&opStartTime, 0);
3180 #endif /* FS_STATS_DETAILED */
3181     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3182         goto Bad_StoreACL;
3183
3184     /* Get ptr to client data for user Id for logging */
3185     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3186     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3187     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3188             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3189             inet_ntoa(logHostAddr), t_client->ViceId));
3190     FS_LOCK
3191     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3192     FS_UNLOCK
3193
3194     InStatus.Mask = 0;      /* not storing any status */
3195
3196     /*
3197      * Get associated volume/vnode for the target dir; caller's rights
3198      * are also returned.
3199      */
3200     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3201                                      MustBeDIR, &parentwhentargetnotdir,
3202                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3203         goto Bad_StoreACL;
3204     }
3205
3206     /* set volume synchronization information */
3207     SetVolumeSync(Sync, volptr);
3208
3209     /* Check if we have permission to change the dir's ACL */
3210     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3211                                            CHK_STOREACL, &InStatus))) {
3212         goto Bad_StoreACL;
3213     }
3214
3215     /* Build and store the new Access List for the dir */
3216     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3217         goto Bad_StoreACL;
3218     }
3219     
3220     targetptr->changed_newTime = 1; /* status change of directory */
3221
3222     /* convert the write lock to a read lock before breaking callbacks */
3223     VVnodeWriteToRead(&errorCode, targetptr);
3224     assert(!errorCode || errorCode == VSALVAGE);
3225
3226     /* break call backs on the directory  */
3227     BreakCallBack(client->host, Fid, 0);
3228
3229     /* Get the updated dir's status back to the caller */
3230     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3231
3232 Bad_StoreACL: 
3233     /* Update and store volume/vnode and parent vnodes back */
3234     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3235     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
3236     CallPostamble(tcon);
3237
3238 #if FS_STATS_DETAILED
3239     TM_GetTimeOfDay(&opStopTime, 0);
3240     if (errorCode == 0) {
3241       FS_LOCK
3242       (opP->numSuccesses)++;
3243       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3244       fs_stats_AddTo((opP->sumTime), elapsedTime);
3245       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3246       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3247         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3248       }
3249       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3250         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3251       }
3252       FS_UNLOCK
3253     }
3254 #endif /* FS_STATS_DETAILED */
3255
3256     osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3257     return errorCode;
3258
3259 } /*SRXAFS_StoreACL*/
3260
3261
3262 /*
3263  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3264  * should be merged when possible.
3265  */
3266 static afs_int32
3267 SAFSS_StoreStatus (struct rx_call *acall,               
3268                    struct AFSFid *Fid,                  
3269                    struct AFSStoreStatus *InStatus,     
3270                    struct AFSFetchStatus *OutStatus,    
3271                    struct AFSVolSync *Sync)
3272
3273 {
3274     Vnode * targetptr = 0;              /* pointer to input fid */
3275     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3276     int     errorCode = 0;              /* return code for caller */
3277     Volume * volptr = 0;                /* pointer to the volume header */
3278     struct client * client;             /* pointer to client structure */
3279     afs_int32 rights, anyrights;                /* rights for this and any user */
3280     struct client *t_client;            /* tmp ptr to client data */
3281     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3282     struct rx_connection *tcon = rx_ConnectionOf(acall);
3283
3284     /* Get ptr to client data for user Id for logging */
3285     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3286     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3287     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
3288             Fid->Volume, Fid->Vnode,    Fid->Unique,
3289             inet_ntoa(logHostAddr), t_client->ViceId));
3290     FS_LOCK
3291     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3292     FS_UNLOCK
3293     /*
3294      * Get volume/vnode for the target file; caller's rights to it are
3295      * also returned
3296      */
3297     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3298                                      DONTCHECK, &parentwhentargetnotdir,
3299                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3300         goto Bad_StoreStatus;
3301     }
3302
3303     /* set volume synchronization information */
3304     SetVolumeSync(Sync, volptr);
3305
3306     /* Check if the caller has proper permissions to store status to Fid */
3307     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3308                                            CHK_STORESTATUS, InStatus))) {
3309         goto Bad_StoreStatus;
3310     }
3311     /*
3312      * Check for a symbolic link; we can't chmod these (otherwise could
3313      * change a symlink to a mt pt or vice versa)
3314      */
3315     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3316         errorCode = EINVAL;
3317         goto Bad_StoreStatus;
3318     }
3319
3320     /* Update the status of the target's vnode */
3321     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3322                              (parentwhentargetnotdir ?
3323                               parentwhentargetnotdir : targetptr), volptr,
3324                              (afs_size_t)0);
3325
3326     /* convert the write lock to a read lock before breaking callbacks */
3327     VVnodeWriteToRead(&errorCode, targetptr);
3328     assert(!errorCode || errorCode == VSALVAGE);
3329
3330     /* Break call backs on Fid */
3331     BreakCallBack(client->host, Fid, 0);
3332
3333     /* Return the updated status back to caller */
3334     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3335
3336 Bad_StoreStatus: 
3337     /* Update and store volume/vnode and parent vnodes back */
3338     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3339     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3340     return errorCode;
3341
3342 } /*SAFSS_StoreStatus*/
3343
3344
3345 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,            
3346                               struct AFSFid *Fid,               
3347                               struct AFSStoreStatus *InStatus,  
3348                               struct AFSFetchStatus *OutStatus, 
3349                               struct AFSVolSync *Sync)
3350 {
3351     afs_int32 code;
3352     struct rx_connection *tcon;
3353 #if FS_STATS_DETAILED
3354     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3355     struct timeval opStartTime,
3356                    opStopTime;              /* Start/stop times for RPC op*/
3357     struct timeval elapsedTime;             /* Transfer time */
3358
3359     /*
3360      * Set our stats pointer, remember when the RPC operation started, and
3361      * tally the operation.
3362      */
3363     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3364     FS_LOCK
3365     (opP->numOps)++;
3366     FS_UNLOCK
3367     TM_GetTimeOfDay(&opStartTime, 0);
3368 #endif /* FS_STATS_DETAILED */
3369
3370     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3371         goto Bad_StoreStatus;
3372
3373     code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3374
3375 Bad_StoreStatus:
3376     CallPostamble(tcon);
3377
3378 #if FS_STATS_DETAILED
3379     TM_GetTimeOfDay(&opStopTime, 0);
3380     if (code == 0) {
3381       FS_LOCK
3382       (opP->numSuccesses)++;
3383       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3384       fs_stats_AddTo((opP->sumTime), elapsedTime);
3385       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3386       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3387         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3388       }
3389       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3390         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3391       }
3392       FS_UNLOCK
3393     }
3394
3395 #endif /* FS_STATS_DETAILED */
3396
3397     osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3398     return code;
3399
3400 } /*SRXAFS_StoreStatus*/
3401
3402
3403 /*
3404  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3405  * merged in when possible.
3406  */
3407 static afs_int32
3408 SAFSS_RemoveFile (struct rx_call *acall,               
3409                   struct AFSFid *DirFid,               
3410                   char *Name,                          
3411                   struct AFSFetchStatus *OutDirStatus, 
3412                   struct AFSVolSync *Sync)
3413 {
3414     Vnode * parentptr = 0;              /* vnode of input Directory */
3415     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3416     Vnode * targetptr = 0;              /* file to be deleted */
3417     Volume * volptr = 0;                /* pointer to the volume header */
3418     AFSFid fileFid;                     /* area for Fid from the directory */
3419     int     errorCode = 0;              /* error code */
3420     DirHandle dir;                      /* Handle for dir package I/O */
3421     struct client * client;             /* pointer to client structure */
3422     afs_int32 rights, anyrights;                /* rights for this and any user */
3423     struct client *t_client;            /* tmp ptr to client data */
3424     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3425     struct rx_connection *tcon = rx_ConnectionOf(acall);
3426
3427     FidZero(&dir);
3428     /* Get ptr to client data for user Id for logging */
3429     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3430     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3431     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3432             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3433             inet_ntoa(logHostAddr), t_client->ViceId));
3434     FS_LOCK
3435     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3436     FS_UNLOCK
3437     /*
3438      * Get volume/vnode for the parent dir; caller's access rights are
3439      * also returned
3440      */
3441     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3442                                      MustBeDIR, &parentwhentargetnotdir,
3443                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3444         goto Bad_RemoveFile;
3445     }
3446     /* set volume synchronization information */
3447     SetVolumeSync(Sync, volptr);
3448
3449     /* Does the caller has delete (& write) access to the parent directory? */
3450     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3451         goto Bad_RemoveFile;
3452     }
3453
3454     /* Actually delete the desired file */
3455     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3456                                  &fileFid, Name, MustNOTBeDIR))) {
3457         goto Bad_RemoveFile;
3458     }
3459
3460     /* Update the vnode status of the parent dir */
3461 #if FS_STATS_DETAILED
3462     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3463                              parentptr->disk.linkCount, client->InSameNetwork);
3464 #else
3465     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3466                              parentptr->disk.linkCount);
3467 #endif /* FS_STATS_DETAILED */
3468
3469     /* Return the updated parent dir's status back to caller */
3470     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3471
3472     /* Handle internal callback state for the parent and the deleted file */
3473     if (targetptr->disk.linkCount == 0) {
3474         /* no references left, discard entry */
3475         DeleteFileCallBacks(&fileFid);
3476         /* convert the parent lock to a read lock before breaking callbacks */
3477         VVnodeWriteToRead(&errorCode, parentptr);
3478         assert(!errorCode || errorCode == VSALVAGE);
3479     } else {
3480         /* convert the parent lock to a read lock before breaking callbacks */
3481         VVnodeWriteToRead(&errorCode, parentptr);
3482         assert(!errorCode || errorCode == VSALVAGE);
3483         /* convert the target lock to a read lock before breaking callbacks */
3484         VVnodeWriteToRead(&errorCode, targetptr);
3485         assert(!errorCode || errorCode == VSALVAGE);
3486         /* tell all the file has changed */
3487         BreakCallBack(client->host, &fileFid, 1);
3488     }
3489
3490     /* break call back on the directory */
3491     BreakCallBack(client->host, DirFid, 0);
3492
3493 Bad_RemoveFile: 
3494     /* Update and store volume/vnode and parent vnodes back */
3495     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3496     FidZap(&dir);
3497     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
3498     return errorCode;
3499
3500 } /*SAFSS_RemoveFile*/
3501
3502
3503 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3504                              struct AFSFid *DirFid,
3505                              char *Name,
3506                              struct AFSFetchStatus *OutDirStatus,
3507                              struct AFSVolSync *Sync)
3508 {
3509     afs_int32 code;
3510     struct rx_connection *tcon;
3511 #if FS_STATS_DETAILED
3512     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3513     struct timeval opStartTime,
3514                    opStopTime;              /* Start/stop times for RPC op*/
3515     struct timeval elapsedTime;             /* Transfer time */
3516
3517     /*
3518      * Set our stats pointer, remember when the RPC operation started, and
3519      * tally the operation.
3520      */
3521     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3522     FS_LOCK
3523     (opP->numOps)++;
3524     FS_UNLOCK
3525     TM_GetTimeOfDay(&opStartTime, 0);
3526 #endif /* FS_STATS_DETAILED */
3527
3528     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3529         goto Bad_RemoveFile;
3530
3531     code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3532
3533 Bad_RemoveFile:    
3534     CallPostamble(tcon);
3535
3536 #if FS_STATS_DETAILED
3537     TM_GetTimeOfDay(&opStopTime, 0);
3538     if (code == 0) {
3539       FS_LOCK
3540       (opP->numSuccesses)++;
3541       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3542       fs_stats_AddTo((opP->sumTime), elapsedTime);
3543       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3544       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3545         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3546       }
3547       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3548         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3549       }
3550       FS_UNLOCK
3551     }
3552
3553 #endif /* FS_STATS_DETAILED */
3554
3555     osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3556     return code;
3557
3558 } /*SRXAFS_RemoveFile*/
3559
3560
3561 /*
3562  * This routine is called exclusively from SRXAFS_CreateFile(), and should
3563  * be merged in when possible.
3564  */
3565 static afs_int32
3566 SAFSS_CreateFile (struct rx_call *acall,
3567                   struct AFSFid *DirFid,
3568                   char *Name,
3569                   struct AFSStoreStatus *InStatus,
3570                   struct AFSFid *OutFid,
3571                   struct AFSFetchStatus *OutFidStatus,
3572                   struct AFSFetchStatus *OutDirStatus,
3573                   struct AFSCallBack *CallBack,
3574                   struct AFSVolSync *Sync)
3575 {
3576     Vnode * parentptr = 0;              /* vnode of input Directory */
3577     Vnode * targetptr = 0;              /* vnode of the new file */
3578     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3579     Volume * volptr = 0;                /* pointer to the volume header */
3580     int     errorCode = 0;              /* error code */
3581     DirHandle dir;                      /* Handle for dir package I/O */
3582     struct client * client;             /* pointer to client structure */
3583     afs_int32 rights, anyrights;        /* rights for this and any user */
3584     struct client *t_client;            /* tmp ptr to client data */
3585     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3586     struct rx_connection *tcon = rx_ConnectionOf(acall);
3587
3588     FidZero(&dir);
3589
3590     /* Get ptr to client data for user Id for logging */
3591     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3592     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3593     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3594             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3595             inet_ntoa(logHostAddr), t_client->ViceId));
3596     FS_LOCK
3597     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3598     FS_UNLOCK
3599     if (!FileNameOK(Name)) {
3600       errorCode = EINVAL;
3601       goto Bad_CreateFile;
3602     }
3603
3604     /*
3605      * Get associated volume/vnode for the parent dir; caller long are
3606      * also returned
3607      */
3608     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3609                                      MustBeDIR, &parentwhentargetnotdir,
3610                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3611         goto Bad_CreateFile;
3612     }
3613
3614     /* set volume synchronization information */
3615     SetVolumeSync(Sync, volptr);
3616
3617     /* Can we write (and insert) onto the parent directory? */
3618     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3619         goto Bad_CreateFile;
3620     }
3621     /* get a new vnode for the file to be created and set it up */
3622     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3623                                    Name, OutFid, vFile, nBlocks(0)))) {
3624         goto Bad_CreateFile;
3625     }
3626
3627     /* update the status of the parent vnode */
3628 #if FS_STATS_DETAILED
3629     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3630                              parentptr->disk.linkCount, client->InSameNetwork);
3631 #else
3632     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3633                              parentptr->disk.linkCount);
3634 #endif /* FS_STATS_DETAILED */
3635
3636     /* update the status of the new file's vnode */
3637     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3638                              parentptr, volptr, (afs_size_t)0);
3639
3640     /* set up the return status for the parent dir and the newly created file */
3641     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3642     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3643
3644     /* convert the write lock to a read lock before breaking callbacks */
3645     VVnodeWriteToRead(&errorCode, parentptr);
3646     assert(!errorCode || errorCode == VSALVAGE);
3647     
3648     /* break call back on parent dir */
3649     BreakCallBack(client->host, DirFid, 0);
3650
3651     /* Return a callback promise for the newly created file to the caller */
3652     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3653
3654 Bad_CreateFile:
3655     /* Update and store volume/vnode and parent vnodes back */
3656     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3657     FidZap(&dir);
3658     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
3659     return errorCode;
3660
3661 } /*SAFSS_CreateFile*/
3662
3663
3664 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3665                              struct AFSFid *DirFid,
3666                              char *Name,
3667                              struct AFSStoreStatus *InStatus,
3668                              struct AFSFid *OutFid,
3669                              struct AFSFetchStatus *OutFidStatus,
3670                              struct AFSFetchStatus *OutDirStatus, 
3671                              struct AFSCallBack *CallBack,       
3672                              struct AFSVolSync *Sync)
3673 {
3674     afs_int32 code;
3675     struct rx_connection *tcon;
3676 #if FS_STATS_DETAILED
3677     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3678     struct timeval opStartTime,
3679                    opStopTime;              /* Start/stop times for RPC op*/
3680     struct timeval elapsedTime;             /* Transfer time */
3681
3682     /*
3683      * Set our stats pointer, remember when the RPC operation started, and
3684      * tally the operation.
3685      */
3686     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3687     FS_LOCK
3688     (opP->numOps)++;
3689     FS_UNLOCK
3690     TM_GetTimeOfDay(&opStartTime, 0);
3691 #endif /* FS_STATS_DETAILED */
3692
3693     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3694         goto Bad_CreateFile;
3695
3696     code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3697                             OutFidStatus, OutDirStatus, CallBack, Sync);
3698
3699 Bad_CreateFile:    
3700     CallPostamble(tcon);
3701
3702 #if FS_STATS_DETAILED
3703     TM_GetTimeOfDay(&opStopTime, 0);
3704     if (code == 0) {
3705       FS_LOCK
3706       (opP->numSuccesses)++;
3707       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3708       fs_stats_AddTo((opP->sumTime), elapsedTime);
3709       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3710       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3711         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3712       }
3713       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3714         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3715       }
3716       FS_UNLOCK
3717     }
3718 #endif /* FS_STATS_DETAILED */
3719
3720     osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3721     return code;
3722
3723 } /*SRXAFS_CreateFile*/
3724
3725
3726 /*
3727  * This routine is called exclusively from SRXAFS_Rename(), and should be
3728  * merged in when possible.
3729  */
3730 static afs_int32
3731 SAFSS_Rename (struct rx_call *acall,
3732               struct AFSFid *OldDirFid,
3733               char *OldName,
3734               struct AFSFid *NewDirFid,
3735               char *NewName,
3736               struct AFSFetchStatus *OutOldDirStatus,
3737               struct AFSFetchStatus *OutNewDirStatus,
3738               struct AFSVolSync *Sync)
3739 {
3740     Vnode * oldvptr = 0;        /* vnode of the old Directory */
3741     Vnode * newvptr = 0;        /* vnode of the new Directory */
3742     Vnode * fileptr = 0;        /* vnode of the file to move */
3743     Vnode * newfileptr = 0;     /* vnode of the file to delete */
3744     Vnode * testvptr = 0;       /* used in directory tree walk */
3745     Vnode * parent = 0;         /* parent for use in SetAccessList */
3746     int     errorCode = 0;      /* error code */
3747     int     fileCode = 0;       /* used when writing Vnodes */
3748     VnodeId testnode;           /* used in directory tree walk */
3749     AFSFid fileFid;             /* Fid of file to move */
3750     AFSFid newFileFid;          /* Fid of new file */
3751     DirHandle olddir;           /* Handle for dir package I/O */
3752     DirHandle newdir;           /* Handle for dir package I/O */
3753     DirHandle filedir;          /* Handle for dir package I/O */
3754     DirHandle newfiledir;       /* Handle for dir package I/O */
3755     Volume * volptr = 0;        /* pointer to the volume header */
3756     struct client * client;     /* pointer to client structure */
3757     afs_int32 rights, anyrights;        /* rights for this and any user */
3758     afs_int32 newrights;                /* rights for this user */
3759     afs_int32 newanyrights;             /* rights for any user */
3760     int doDelete;               /* deleted the rename target (ref count now 0) */
3761     int code;
3762     struct client *t_client;            /* tmp ptr to client data */
3763     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3764     struct rx_connection *tcon = rx_ConnectionOf(acall);
3765
3766     FidZero(&olddir);
3767     FidZero(&newdir);
3768     FidZero(&filedir);
3769     FidZero(&newfiledir);
3770
3771     /* Get ptr to client data for user Id for logging */
3772     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3773     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3774     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3775             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3776             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3777             NewDirFid->Unique,
3778             inet_ntoa(logHostAddr), t_client->ViceId));
3779     FS_LOCK
3780     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3781     FS_UNLOCK
3782     if (!FileNameOK(NewName)) {
3783         errorCode = EINVAL;
3784         goto Bad_Rename;
3785     }
3786     if (OldDirFid->Volume != NewDirFid->Volume) {
3787         DFlush();
3788         errorCode = EXDEV;
3789         goto Bad_Rename;
3790     }
3791     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3792          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
3793          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
3794         DFlush();
3795         errorCode = EINVAL;
3796         goto Bad_Rename;
3797     }
3798
3799     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3800         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3801                                           &oldvptr, MustBeDIR, &parent,
3802                                           &client, WRITE_LOCK, &rights,
3803                                           &anyrights)) {
3804             DFlush();
3805             goto Bad_Rename;
3806         }
3807         if (OldDirFid->Vnode == NewDirFid->Vnode) {
3808             newvptr = oldvptr;
3809             newrights = rights, newanyrights = anyrights;
3810         }
3811         else
3812             if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3813                                              &newvptr, MustBeDIR, &parent,
3814                                              &client, WRITE_LOCK, &newrights,
3815                                              &newanyrights))) {
3816                 DFlush();
3817                 goto Bad_Rename;
3818             }
3819     }
3820     else {
3821         if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3822                                          &newvptr, MustBeDIR, &parent,
3823                                          &client, WRITE_LOCK, &newrights,
3824                                          &newanyrights))) {
3825             DFlush();
3826             goto Bad_Rename;
3827         }
3828         if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3829                                          MustBeDIR, &parent, &client, WRITE_LOCK,
3830                                          &rights, &anyrights))) {
3831             DFlush();
3832             goto Bad_Rename;
3833         }
3834     }
3835
3836     /* set volume synchronization information */
3837     SetVolumeSync(Sync, volptr);
3838
3839     if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3840         goto Bad_Rename;
3841     }
3842     if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3843         goto Bad_Rename;
3844     }
3845
3846     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3847     *  call to CopyOnWrite returns error, it is not necessary to revert back
3848     *  the effects of the first call because the contents of the volume is 
3849     *  not modified, it is only replicated.
3850     */
3851     if (oldvptr->disk.cloned)
3852     {
3853         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
3854          if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3855                 goto Bad_Rename;
3856     }
3857     SetDirHandle(&olddir, oldvptr);
3858     if (newvptr->disk.cloned)
3859     {
3860         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
3861         if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3862                 goto Bad_Rename;        
3863     }
3864
3865     SetDirHandle(&newdir, newvptr);
3866
3867     /* Lookup the file to delete its vnode */
3868     if (Lookup(&olddir, OldName, &fileFid)) {
3869         errorCode = ENOENT;
3870         goto Bad_Rename;
3871     }
3872     if (fileFid.Vnode == oldvptr->vnodeNumber ||
3873         fileFid.Vnode == newvptr->vnodeNumber) {
3874         errorCode = FSERR_ELOOP;
3875         goto Bad_Rename;
3876     }
3877     fileFid.Volume = V_id(volptr);
3878     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3879     if (errorCode != 0) {
3880         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3881         VTakeOffline (volptr);
3882         goto Bad_Rename;
3883     }
3884     if (fileptr->disk.uniquifier != fileFid.Unique) {
3885         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3886         VTakeOffline (volptr);
3887         errorCode = EIO;
3888         goto Bad_Rename;
3889     }
3890
3891     if (fileptr->disk.type != vDirectory &&
3892         oldvptr != newvptr &&
3893         fileptr->disk.linkCount != 1) {
3894         /*
3895          * Hard links exist to this file - cannot move one of the links to
3896          * a new directory because of AFS restrictions (this is the same
3897          * reason that links cannot be made across directories, i.e.
3898          * access lists)
3899          */
3900         errorCode = EXDEV;
3901         goto Bad_Rename;
3902     }
3903
3904     /* Lookup the new file  */
3905     if (!(Lookup(&newdir, NewName, &newFileFid))) {
3906         if (readonlyServer) {
3907             errorCode = VREADONLY;
3908             goto Bad_Rename;
3909         }
3910         if (!(newrights & PRSFS_DELETE)) {
3911             errorCode = EACCES;
3912             goto Bad_Rename;
3913         }
3914         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3915                 newFileFid.Vnode == newvptr->vnodeNumber ||
3916                 newFileFid.Vnode == fileFid.Vnode) {
3917             errorCode = EINVAL;
3918             goto Bad_Rename;
3919         }
3920         newFileFid.Volume = V_id(volptr);
3921         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3922         if (errorCode != 0) {
3923             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3924             VTakeOffline (volptr);
3925             goto Bad_Rename;
3926         }
3927         if (fileptr->disk.uniquifier != fileFid.Unique) {
3928             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3929             VTakeOffline (volptr);
3930             errorCode = EIO;
3931             goto Bad_Rename;
3932         }
3933         SetDirHandle(&newfiledir, newfileptr);
3934         /* Now check that we're moving directories over directories properly, etc.
3935          * return proper POSIX error codes:
3936          * if fileptr is a file and new is a dir: EISDIR.
3937          * if fileptr is a dir and new is a file: ENOTDIR.
3938          * Also, dir to be removed must be empty, of course.
3939          */
3940         if (newfileptr->disk.type == vDirectory) {
3941             if (fileptr->disk.type != vDirectory) {
3942                 errorCode = EISDIR;
3943                 goto Bad_Rename;
3944             }
3945             if ((IsEmpty(&newfiledir))) {
3946                 errorCode = EEXIST;
3947                 goto Bad_Rename;
3948             }
3949         }
3950         else {
3951             if (fileptr->disk.type == vDirectory) {
3952                 errorCode = ENOTDIR;
3953                 goto Bad_Rename;
3954             }
3955         }
3956     }
3957
3958     /*
3959      * ok - now we check that the old name is not above new name in the
3960      * directory structure.  This is to prevent removing a subtree alltogether
3961      */
3962     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3963         for (testnode = newvptr->disk.parent; testnode != 0;) {
3964             if (testnode == oldvptr->vnodeNumber) {
3965                 testnode = oldvptr->disk.parent;
3966                 continue;
3967             }
3968             if ((testnode == fileptr->vnodeNumber) ||
3969                 (testnode == newvptr->vnodeNumber)) {
3970                 errorCode = FSERR_ELOOP;
3971                 goto Bad_Rename;
3972             }
3973             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3974                 errorCode = FSERR_ELOOP;
3975                 goto Bad_Rename;
3976             }
3977             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3978             assert(errorCode == 0);
3979             testnode = testvptr->disk.parent;
3980             VPutVnode(&errorCode, testvptr);
3981             assert(errorCode == 0);
3982         }
3983     }
3984     /* Do the CopyonWrite first before modifying anything else. Copying is
3985      *  required because we may have to change entries for .. 
3986      */
3987     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3988     {
3989         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
3990         if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3991                 goto Bad_Rename;
3992     }
3993
3994     /* If the new name exists already, delete it and the file it points to */
3995     doDelete = 0;
3996     if (newfileptr) {
3997         /* Delete NewName from its directory */
3998         code = Delete(&newdir, NewName);
3999         assert(code == 0);
4000
4001         /* Drop the link count */
4002         newfileptr->disk.linkCount--;
4003         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
4004             afs_size_t  newSize;
4005             VN_GET_LEN(newSize, newfileptr);
4006             VAdjustDiskUsage(&errorCode, volptr,
4007                              -nBlocks(newSize), (afs_size_t) 0);
4008             if (VN_GET_INO(newfileptr)) {
4009                 IH_REALLYCLOSE(newfileptr->handle);
4010                 errorCode = IH_DEC(V_linkHandle(volptr),
4011                                  VN_GET_INO(newfileptr),
4012                                  V_parentId(volptr));
4013                 IH_RELEASE(newfileptr->handle);
4014                 if (errorCode == -1) {
4015                     ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
4016                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
4017                                 NewName, errno));
4018                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
4019                         ViceLog(0, ("Do we need to fsck?"));
4020                 } 
4021             }
4022             VN_SET_INO(newfileptr, (Inode)0);
4023             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
4024             doDelete = 1;
4025         } else {
4026             /* Link count did not drop to zero.
4027              * Mark NewName vnode as changed - updates stime.
4028              */
4029             newfileptr->changed_newTime = 1;
4030         }
4031     }
4032     
4033     /*
4034      * If the create below fails, and the delete above worked, we have
4035      * removed the new name and not replaced it.  This is not very likely,
4036      * but possible.  We could try to put the old file back, but it is
4037      * highly unlikely that it would work since it would involve issuing
4038      * another create.
4039      */
4040     if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
4041         goto Bad_Rename;
4042
4043     /* Delete the old name */
4044     assert(Delete(&olddir,(char *) OldName) == 0);
4045
4046     /* if the directory length changes, reflect it in the statistics */
4047 #if FS_STATS_DETAILED
4048     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4049                              oldvptr->disk.linkCount, client->InSameNetwork);
4050     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4051                              newvptr->disk.linkCount, client->InSameNetwork);
4052 #else
4053     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4054                              oldvptr->disk.linkCount);
4055     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4056                              newvptr->disk.linkCount);
4057 #endif /* FS_STATS_DETAILED */
4058
4059     if (oldvptr == newvptr)
4060         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
4061
4062     fileptr->disk.parent = newvptr->vnodeNumber;
4063     fileptr->changed_newTime = 1;       /* status change of moved file */
4064
4065     /* if we are dealing with a rename of a directory */
4066     if (fileptr->disk.type == vDirectory) {
4067         assert(!fileptr->disk.cloned);          
4068         SetDirHandle(&filedir, fileptr);
4069         /* fix .. to point to the correct place */
4070         Delete(&filedir, ".."); /* No assert--some directories may be bad */
4071         assert(Create(&filedir, "..", NewDirFid) == 0);
4072         fileptr->disk.dataVersion++;
4073         /* if the parent directories are different the link counts have to be   */
4074         /* changed due to .. in the renamed directory */
4075         if (oldvptr != newvptr) {
4076             oldvptr->disk.linkCount--;
4077             newvptr->disk.linkCount++;
4078         }
4079     }
4080
4081     /* set up return status */
4082     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
4083     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
4084     if (newfileptr && doDelete) {
4085         DeleteFileCallBacks(&newFileFid);       /* no other references */
4086     }
4087
4088     DFlush();
4089
4090     /* convert the write locks to a read locks before breaking callbacks */
4091     VVnodeWriteToRead(&errorCode, newvptr);
4092     assert(!errorCode || errorCode == VSALVAGE);
4093     if (oldvptr != newvptr) {
4094         VVnodeWriteToRead(&errorCode, oldvptr);
4095         assert(!errorCode || errorCode == VSALVAGE);
4096     }
4097     if (newfileptr && !doDelete) {
4098         /* convert the write lock to a read lock before breaking callbacks */
4099         VVnodeWriteToRead(&errorCode, newfileptr);
4100         assert(!errorCode || errorCode == VSALVAGE);
4101     }
4102
4103     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
4104     BreakCallBack(client->host, NewDirFid, 0);
4105     if (oldvptr != newvptr) {
4106         BreakCallBack(client->host, OldDirFid, 0);
4107         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
4108             BreakCallBack(client->host, &fileFid, 0);
4109     }
4110     if (newfileptr) {
4111         /* Note:  it is not necessary to break the callback */
4112         if (doDelete)
4113             DeleteFileCallBacks(&newFileFid);   /* no other references */
4114         else
4115             /* other's still exist (with wrong link count) */
4116             BreakCallBack(client->host, &newFileFid, 1);
4117     }
4118
4119 Bad_Rename: 
4120     if (newfileptr) {
4121         VPutVnode(&fileCode, newfileptr);
4122         assert(fileCode == 0);
4123     }
4124     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
4125                      oldvptr, volptr);
4126     FidZap(&olddir);
4127     FidZap(&newdir);
4128     FidZap(&filedir);
4129     FidZap(&newfiledir);
4130     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4131     return errorCode;
4132
4133 } /*SAFSS_Rename*/
4134
4135
4136 afs_int32 SRXAFS_Rename (struct rx_call *acall,              
4137                          struct AFSFid *OldDirFid,                   
4138                          char *OldName,                      
4139                          struct AFSFid *NewDirFid,
4140                          char *NewName,
4141                          struct AFSFetchStatus *OutOldDirStatus,
4142                          struct AFSFetchStatus *OutNewDirStatus,
4143                          struct AFSVolSync *Sync)
4144 {
4145     afs_int32 code;
4146     struct rx_connection *tcon;
4147 #if FS_STATS_DETAILED
4148     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4149     struct timeval opStartTime,
4150                    opStopTime;              /* Start/stop times for RPC op*/
4151     struct timeval elapsedTime;             /* Transfer time */
4152
4153     /*
4154      * Set our stats pointer, remember when the RPC operation started, and
4155      * tally the operation.
4156      */
4157     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4158     FS_LOCK
4159     (opP->numOps)++;
4160     FS_UNLOCK
4161     TM_GetTimeOfDay(&opStartTime, 0);
4162 #endif /* FS_STATS_DETAILED */
4163
4164     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4165         goto Bad_Rename;
4166
4167     code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4168                          OutOldDirStatus, OutNewDirStatus, Sync);
4169
4170 Bad_Rename:    
4171     CallPostamble(tcon);
4172
4173 #if FS_STATS_DETAILED
4174     TM_GetTimeOfDay(&opStopTime, 0);
4175     if (code == 0) {
4176       FS_LOCK
4177       (opP->numSuccesses)++;
4178       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4179       fs_stats_AddTo((opP->sumTime), elapsedTime);
4180       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4181       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4182         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4183       }
4184       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4185         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4186       }
4187       FS_UNLOCK
4188     }
4189
4190 #endif /* FS_STATS_DETAILED */
4191
4192     osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
4193     return code;
4194
4195 } /*SRXAFS_Rename*/
4196
4197
4198 /*
4199  * This routine is called exclusively by SRXAFS_Symlink(), and should be
4200  * merged into it when possible.
4201  */
4202 static afs_int32 
4203 SAFSS_Symlink (struct rx_call *acall,
4204                struct AFSFid *DirFid,
4205                char *Name,
4206                char *LinkContents,
4207                struct AFSStoreStatus *InStatus,
4208                struct AFSFid *OutFid,
4209                struct AFSFetchStatus *OutFidStatus,
4210                struct AFSFetchStatus *OutDirStatus,
4211                struct AFSVolSync *Sync)         
4212
4213 {
4214     Vnode * parentptr = 0;              /* vnode of input Directory */
4215     Vnode * targetptr = 0;              /* vnode of the new link */
4216     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4217     int     errorCode = 0;              /* error code */
4218     int code = 0;
4219     DirHandle dir;                      /* Handle for dir package I/O */
4220     Volume * volptr = 0;                /* pointer to the volume header */
4221     struct client * client;             /* pointer to client structure */
4222     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
4223     struct client *t_client;            /* tmp ptr to client data */
4224     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4225     FdHandle_t *fdP;
4226     struct rx_connection *tcon = rx_ConnectionOf(acall);
4227
4228     FidZero(&dir);
4229
4230     /* Get ptr to client data for user Id for logging */
4231     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4232     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4233     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
4234             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4235             inet_ntoa(logHostAddr), t_client->ViceId));
4236     FS_LOCK
4237     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
4238     FS_UNLOCK
4239     if (!FileNameOK(Name)) {
4240         errorCode = EINVAL;
4241         goto Bad_SymLink;
4242     }
4243
4244     /*
4245      * Get the vnode and volume for the parent dir along with the caller's
4246      * rights to it
4247      */
4248     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4249                                      MustBeDIR, &parentwhentargetnotdir,
4250                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4251         goto Bad_SymLink;
4252     }
4253
4254     /* set volume synchronization information */
4255     SetVolumeSync(Sync, volptr);
4256
4257     /* Does the caller has insert (and write) access to the parent directory? */
4258     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4259         goto Bad_SymLink;
4260     }
4261
4262     /*
4263      * If we're creating a mount point (any x bits clear), we must have
4264      * administer access to the directory, too.  Always allow sysadmins
4265      * to do this.
4266      */
4267     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
4268         if (readonlyServer) {
4269             errorCode = VREADONLY;
4270             goto Bad_SymLink;
4271         }
4272         /*
4273          * We have a mountpoint, 'cause we're trying to set the Unix mode
4274          * bits to something with some x bits missing (default mode bits
4275          * if AFS_SETMODE is false is 0777)
4276          */
4277         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
4278             errorCode = EACCES;
4279             goto Bad_SymLink;
4280         }
4281     }
4282  
4283     /* get a new vnode for the symlink and set it up */
4284     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
4285                                    Name, OutFid, vSymlink,
4286                                    nBlocks(strlen((char *) LinkContents))))) {
4287         goto Bad_SymLink;
4288     }
4289
4290     /* update the status of the parent vnode */
4291 #if FS_STATS_DETAILED
4292     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4293                              parentptr->disk.linkCount, client->InSameNetwork);
4294 #else
4295     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4296                              parentptr->disk.linkCount);
4297 #endif /* FS_STATS_DETAILED */
4298
4299     /* update the status of the new symbolic link file vnode */
4300     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
4301                              volptr, (afs_size_t)strlen((char *)LinkContents));
4302
4303     /* Write the contents of the symbolic link name into the target inode */
4304     fdP = IH_OPEN(targetptr->handle);
4305     assert(fdP != NULL);
4306     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
4307     FDH_CLOSE(fdP);
4308     /*
4309      * Set up and return modified status for the parent dir and new symlink
4310      * to caller.
4311      */
4312     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4313     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4314
4315     /* convert the write lock to a read lock before breaking callbacks */
4316     VVnodeWriteToRead(&errorCode, parentptr);
4317     assert(!errorCode || errorCode == VSALVAGE);
4318
4319     /* break call back on the parent dir */
4320     BreakCallBack(client->host, DirFid, 0);
4321
4322 Bad_SymLink: 
4323     /* Write the all modified vnodes (parent, new files) and volume back */
4324     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4325     FidZap(&dir);
4326     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
4327     return errorCode;
4328
4329 } /*SAFSS_Symlink*/
4330
4331
4332 afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
4333     struct AFSVolSync *Sync;
4334     struct rx_call *acall;               /* Rx call */
4335     struct AFSFid *DirFid;               /* Parent dir's fid */
4336     char *Name;                          /* File name to create */
4337     char *LinkContents;                  /* Contents of the new created file */
4338     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
4339     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
4340     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
4341     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
4342
4343 {
4344     afs_int32 code;
4345     struct rx_connection *tcon;
4346 #if FS_STATS_DETAILED
4347     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4348     struct timeval opStartTime,
4349                    opStopTime;              /* Start/stop times for RPC op*/
4350     struct timeval elapsedTime;             /* Transfer time */
4351
4352     /*
4353      * Set our stats pointer, remember when the RPC operation started, and
4354      * tally the operation.
4355      */
4356     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
4357     FS_LOCK
4358     (opP->numOps)++;
4359     FS_UNLOCK
4360     TM_GetTimeOfDay(&opStartTime, 0);
4361 #endif /* FS_STATS_DETAILED */
4362
4363     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4364         goto Bad_Symlink;
4365
4366     code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
4367                          OutFidStatus, OutDirStatus, Sync);
4368
4369 Bad_Symlink:    
4370     CallPostamble(tcon);
4371
4372 #if FS_STATS_DETAILED
4373     TM_GetTimeOfDay(&opStopTime, 0);
4374     if (code == 0) {
4375       FS_LOCK
4376       (opP->numSuccesses)++;
4377       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4378       fs_stats_AddTo((opP->sumTime), elapsedTime);
4379       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4380       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4381         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4382       }
4383       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4384         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4385       }
4386       FS_UNLOCK
4387     }
4388
4389 #endif /* FS_STATS_DETAILED */
4390
4391     osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4392     return code;
4393
4394 } /*SRXAFS_Symlink*/
4395
4396
4397 /*
4398  * This routine is called exclusively by SRXAFS_Link(), and should be
4399  * merged into it when possible.
4400  */
4401 static afs_int32 
4402 SAFSS_Link (struct rx_call *acall,
4403             struct AFSFid *DirFid,
4404             char *Name,
4405             struct AFSFid *ExistingFid,
4406             struct AFSFetchStatus *OutFidStatus,
4407             struct AFSFetchStatus *OutDirStatus,
4408             struct AFSVolSync *Sync)
4409 {
4410     Vnode * parentptr = 0;              /* vnode of input Directory */
4411     Vnode * targetptr = 0;              /* vnode of the new file */
4412     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4413     Volume * volptr = 0;                /* pointer to the volume header */
4414     int     errorCode = 0;              /* error code */
4415     DirHandle dir;                      /* Handle for dir package I/O */
4416     struct client * client;             /* pointer to client structure */
4417     afs_int32 rights, anyrights;                /* rights for this and any user */
4418     struct client *t_client;            /* tmp ptr to client data */
4419     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4420     struct rx_connection *tcon = rx_ConnectionOf(acall);
4421
4422     FidZero(&dir);
4423
4424     /* Get ptr to client data for user Id for logging */
4425     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4426     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4427     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
4428             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4429             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
4430             inet_ntoa(logHostAddr), t_client->ViceId));
4431     FS_LOCK
4432     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
4433     FS_UNLOCK
4434     if (DirFid->Volume != ExistingFid->Volume) {
4435         errorCode = EXDEV;
4436         goto Bad_Link;
4437     }
4438     if (!FileNameOK(Name)) {
4439         errorCode = EINVAL;
4440         goto Bad_Link;
4441     }
4442
4443     /*
4444      * Get the vnode and volume for the parent dir along with the caller's
4445      * rights to it
4446      */
4447     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4448                                      MustBeDIR, &parentwhentargetnotdir,
4449                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4450         goto Bad_Link;
4451     }
4452
4453     /* set volume synchronization information */
4454     SetVolumeSync(Sync, volptr);
4455
4456     /* Can the caller insert into the parent directory? */
4457     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4458         goto Bad_Link;
4459     }
4460
4461     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
4462         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
4463       /* AFS fileservers always have directory vnodes that are odd.   */
4464       errorCode = EISDIR;
4465       goto Bad_Link;
4466     }
4467
4468     /* get the file vnode  */
4469     if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
4470         goto Bad_Link;
4471     }
4472     if (targetptr->disk.type != vFile) {
4473         errorCode = EISDIR;
4474         goto Bad_Link;
4475     }
4476     if (targetptr->disk.parent != DirFid->Vnode) {
4477         errorCode = EXDEV;
4478         goto Bad_Link;
4479     }
4480     if (parentptr->disk.cloned) 
4481     {
4482         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
4483         if ( ( errorCode = CopyOnWrite(parentptr, volptr)))
4484                 goto Bad_Link;          /* disk full error */
4485     }
4486
4487     /* add the name to the directory */
4488     SetDirHandle(&dir, parentptr);
4489     if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
4490         goto Bad_Link;
4491     DFlush();
4492
4493     /* update the status in the parent vnode */
4494     /**WARNING** --> disk.author SHOULDN'T be modified???? */
4495 #if FS_STATS_DETAILED
4496     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4497                              parentptr->disk.linkCount, client->InSameNetwork);
4498 #else
4499     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4500                              parentptr->disk.linkCount);
4501 #endif /* FS_STATS_DETAILED */
4502
4503     targetptr->disk.linkCount++;
4504     targetptr->disk.author = client->ViceId;
4505     targetptr->changed_newTime = 1; /* Status change of linked-to file */
4506
4507     /* set up return status */
4508     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4509     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4510
4511     /* convert the write locks to read locks before breaking callbacks */
4512     VVnodeWriteToRead(&errorCode, targetptr);
4513     assert(!errorCode || errorCode == VSALVAGE);
4514     VVnodeWriteToRead(&errorCode, parentptr);
4515     assert(!errorCode || errorCode == VSALVAGE);
4516     
4517     /* break call back on DirFid */
4518     BreakCallBack(client->host, DirFid, 0);
4519     /*
4520      * We also need to break the callback for the file that is hard-linked since part 
4521      * of its status (like linkcount) is changed
4522      */
4523     BreakCallBack(client->host, ExistingFid, 0);
4524
4525 Bad_Link:
4526     /* Write the all modified vnodes (parent, new files) and volume back */
4527     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4528     FidZap(&dir);
4529     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
4530     return errorCode;
4531
4532 } /*SAFSS_Link*/
4533
4534
4535 afs_int32 SRXAFS_Link (struct rx_call *acall,
4536                        struct AFSFid *DirFid,
4537                        char *Name,
4538                        struct AFSFid *ExistingFid,
4539                        struct AFSFetchStatus *OutFidStatus,
4540                        struct AFSFetchStatus *OutDirStatus,
4541                        struct AFSVolSync *Sync)
4542 {
4543     afs_int32 code;
4544     struct rx_connection *tcon;
4545 #if FS_STATS_DETAILED
4546     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4547     struct timeval opStartTime,
4548                    opStopTime;              /* Start/stop times for RPC op*/
4549     struct timeval elapsedTime;             /* Transfer time */
4550
4551     /*
4552      * Set our stats pointer, remember when the RPC operation started, and
4553      * tally the operation.
4554      */
4555     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
4556     FS_LOCK
4557     (opP->numOps)++;
4558     FS_UNLOCK
4559     TM_GetTimeOfDay(&opStartTime, 0);
4560 #endif /* FS_STATS_DETAILED */
4561
4562     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4563         goto Bad_Link;
4564
4565     code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
4566                       OutDirStatus, Sync);
4567     
4568 Bad_Link:
4569     CallPostamble(tcon);
4570
4571 #if FS_STATS_DETAILED
4572     TM_GetTimeOfDay(&opStopTime, 0);
4573     if (code == 0) {
4574       FS_LOCK
4575       (opP->numSuccesses)++;
4576       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4577       fs_stats_AddTo((opP->sumTime), elapsedTime);
4578       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4579       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4580         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4581       }
4582       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4583         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4584       }
4585       FS_UNLOCK
4586     }
4587
4588 #endif /* FS_STATS_DETAILED */
4589
4590     osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
4591     return code;
4592
4593 } /*SRXAFS_Link*/
4594
4595
4596 /*
4597  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4598  * merged into it when possible.
4599  */
4600 static afs_int32
4601 SAFSS_MakeDir (struct rx_call *acall,
4602                struct AFSFid *DirFid,
4603                char *Name,
4604                struct AFSStoreStatus *InStatus,
4605                struct AFSFid *OutFid,
4606                struct AFSFetchStatus *OutFidStatus,
4607                struct AFSFetchStatus *OutDirStatus,
4608                struct AFSCallBack *CallBack,
4609                struct AFSVolSync *Sync)
4610
4611 {
4612     Vnode * parentptr = 0;              /* vnode of input Directory */
4613     Vnode * targetptr = 0;              /* vnode of the new file */
4614     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4615     Volume * volptr = 0;                /* pointer to the volume header */
4616     int     errorCode = 0;              /* error code */
4617     struct acl_accessList * newACL;     /* Access list */
4618     int     newACLSize;                 /* Size of access list */
4619     DirHandle dir;                      /* Handle for dir package I/O */
4620     DirHandle parentdir;                /* Handle for dir package I/O */
4621     struct client * client;             /* pointer to client structure */
4622     afs_int32 rights, anyrights;                /* rights for this and any user */
4623     struct client *t_client;            /* tmp ptr to client data */
4624     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4625     struct rx_connection *tcon = rx_ConnectionOf(acall);
4626
4627     FidZero(&dir);
4628     FidZero(&parentdir);
4629
4630     /* Get ptr to client data for user Id for logging */
4631     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4632     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4633     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4634             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4635             inet_ntoa(logHostAddr), t_client->ViceId));
4636     FS_LOCK
4637     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
4638     FS_UNLOCK
4639     if (!FileNameOK(Name)) {
4640         errorCode = EINVAL;
4641         goto Bad_MakeDir;
4642     }
4643
4644     /*
4645      * Get the vnode and volume for the parent dir along with the caller's
4646      * rights to it.
4647      */
4648     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4649                                      MustBeDIR, &parentwhentargetnotdir,
4650                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4651         goto Bad_MakeDir;
4652     }
4653  
4654     /* set volume synchronization information */
4655     SetVolumeSync(Sync, volptr);
4656
4657     /* Write access to the parent directory? */
4658 #ifdef DIRCREATE_NEED_WRITE
4659     /*
4660      * requires w access for the user to create a directory. this
4661      * closes a loophole in the current security arrangement, since a
4662      * user with i access only can create a directory and get the
4663      * implcit a access that goes with dir ownership, and proceed to 
4664      * subvert quota in the volume.
4665      */
4666     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
4667         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
4668 #else 
4669     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4670 #endif /* DIRCREATE_NEED_WRITE */ 
4671         goto Bad_MakeDir;
4672     }
4673
4674 #define EMPTYDIRBLOCKS 2
4675     /* get a new vnode and set it up */
4676     if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
4677                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) {
4678         goto Bad_MakeDir;
4679     }
4680
4681     /* Update the status for the parent dir */
4682 #if FS_STATS_DETAILED
4683     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4684                              parentptr->disk.linkCount+1, client->InSameNetwork);
4685 #else
4686     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4687                              parentptr->disk.linkCount+1);
4688 #endif /* FS_STATS_DETAILED */
4689
4690     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4691     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
4692                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
4693     assert(parentwhentargetnotdir == 0);
4694     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
4695
4696     /* update the status for the target vnode */
4697     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
4698                              parentptr, volptr, (afs_size_t)0);
4699
4700     /* Actually create the New directory in the directory package */ 
4701     SetDirHandle(&dir, targetptr);
4702     assert(!(MakeDir(&dir, OutFid, DirFid)));
4703     DFlush();
4704     VN_SET_LEN(targetptr, (afs_size_t) Length(&dir));
4705
4706     /* set up return status */
4707     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4708     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4709
4710     /* convert the write lock to a read lock before breaking callbacks */
4711     VVnodeWriteToRead(&errorCode, parentptr);
4712     assert(!errorCode || errorCode == VSALVAGE);
4713
4714     /* break call back on DirFid */
4715     BreakCallBack(client->host, DirFid, 0);
4716
4717     /* Return a callback promise to caller */
4718     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
4719
4720 Bad_MakeDir: 
4721     /* Write the all modified vnodes (parent, new files) and volume back */
4722     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4723     FidZap(&dir);
4724     FidZap(&parentdir);
4725     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
4726     return errorCode;
4727
4728 } /*SAFSS_MakeDir*/
4729
4730
4731 afs_int32 SRXAFS_MakeDir (struct rx_call *acall,
4732                           struct AFSFid *DirFid,
4733                           char *Name,
4734                           struct AFSStoreStatus *InStatus,
4735                           struct AFSFid *OutFid,
4736                           struct AFSFetchStatus *OutFidStatus,
4737                           struct AFSFetchStatus *OutDirStatus,
4738                           struct AFSCallBack *CallBack,
4739                           struct AFSVolSync *Sync)
4740 {
4741     afs_int32 code;
4742     struct rx_connection *tcon;
4743 #if FS_STATS_DETAILED
4744     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4745     struct timeval opStartTime,
4746                    opStopTime;              /* Start/stop times for RPC op*/
4747     struct timeval elapsedTime;             /* Transfer time */
4748
4749     /*
4750      * Set our stats pointer, remember when the RPC operation started, and
4751      * tally the operation.
4752      */
4753     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
4754     FS_LOCK
4755     (opP->numOps)++;
4756     FS_UNLOCK
4757     TM_GetTimeOfDay(&opStartTime, 0);
4758 #endif /* FS_STATS_DETAILED */
4759     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4760         goto Bad_MakeDir;
4761
4762     code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
4763                          OutFidStatus, OutDirStatus, CallBack, Sync);
4764     
4765 Bad_MakeDir:
4766     CallPostamble(tcon);
4767
4768 #if FS_STATS_DETAILED
4769     TM_GetTimeOfDay(&opStopTime, 0);
4770     if (code == 0) {
4771       FS_LOCK
4772       (opP->numSuccesses)++;
4773       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4774       fs_stats_AddTo((opP->sumTime), elapsedTime);
4775       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4776       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4777         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4778       }
4779       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4780         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4781       }
4782       FS_UNLOCK
4783     }
4784
4785 #endif /* FS_STATS_DETAILED */
4786
4787     osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4788     return code;
4789
4790 } /*SRXAFS_MakeDir*/
4791
4792
4793 /*
4794  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4795  * merged into it when possible.
4796  */
4797 static afs_int32
4798 SAFSS_RemoveDir (struct rx_call *acall,
4799                  struct AFSFid *DirFid,
4800                  char *Name,
4801                  struct AFSFetchStatus *OutDirStatus,
4802                  struct AFSVolSync *Sync)
4803
4804 {
4805     Vnode * parentptr = 0;              /* vnode of input Directory */
4806     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4807     Vnode * targetptr = 0;              /* file to be deleted */
4808     AFSFid fileFid;                     /* area for Fid from the directory */
4809     int     errorCode = 0;              /* error code */
4810     DirHandle dir;                      /* Handle for dir package I/O */
4811     Volume * volptr = 0;                /* pointer to the volume header */
4812     struct client * client;             /* pointer to client structure */
4813     afs_int32 rights, anyrights;                /* rights for this and any user */
4814     Vnode debugvnode1, debugvnode2;
4815     struct client *t_client;            /* tmp ptr to client data */
4816     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4817     struct rx_connection *tcon = rx_ConnectionOf(acall);
4818
4819     FidZero(&dir);
4820
4821     /* Get ptr to client data for user Id for logging */
4822     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4823     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4824     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4825             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4826             inet_ntoa(logHostAddr), t_client->ViceId));
4827     FS_LOCK
4828     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
4829     FS_UNLOCK
4830     /*
4831      * Get the vnode and volume for the parent dir along with the caller's
4832      * rights to it
4833      */
4834     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4835                                      MustBeDIR, &parentwhentargetnotdir,
4836                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4837         goto Bad_RemoveDir;
4838     }
4839     debugvnode1 = *parentptr;
4840
4841     /* set volume synchronization information */
4842     SetVolumeSync(Sync, volptr);
4843
4844     /* Does the caller has delete (&write) access to the parent dir? */
4845     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
4846         goto Bad_RemoveDir;
4847     }
4848
4849     debugvnode2 = *parentptr;
4850     /* Do the actual delete of the desired (empty) directory, Name */
4851     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
4852                                  Name, MustBeDIR))) {
4853         goto Bad_RemoveDir;
4854     }
4855
4856     /* Update the status for the parent dir; link count is also adjusted */
4857 #if FS_STATS_DETAILED
4858     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4859                              parentptr->disk.linkCount-1, client->InSameNetwork);
4860 #else
4861     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4862                              parentptr->disk.linkCount-1);
4863 #endif /* FS_STATS_DETAILED */
4864
4865     /* Return to the caller the updated parent dir status */
4866     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4867
4868     /*
4869      * Note: it is not necessary to break the callback on fileFid, since
4870      * refcount is now 0, so no one should be able to refer to the dir
4871      * any longer
4872      */
4873     DeleteFileCallBacks(&fileFid);
4874
4875     /* convert the write lock to a read lock before breaking callbacks */
4876     VVnodeWriteToRead(&errorCode, parentptr);
4877     assert(!errorCode || errorCode == VSALVAGE);
4878
4879     /* break call back on DirFid and fileFid */
4880     BreakCallBack(client->host, DirFid, 0);
4881
4882 Bad_RemoveDir: 
4883     /* Write the all modified vnodes (parent, new files) and volume back */
4884     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4885     FidZap(&dir);
4886     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
4887     return errorCode;
4888
4889 } /*SAFSS_RemoveDir*/
4890
4891
4892 afs_int32 SRXAFS_RemoveDir (struct rx_call *acall,
4893                             struct AFSFid *DirFid,
4894                             char *Name,
4895                             struct AFSFetchStatus *OutDirStatus,
4896                             struct AFSVolSync *Sync)
4897 {
4898     afs_int32 code;
4899     struct rx_connection *tcon;
4900 #if FS_STATS_DETAILED
4901     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4902     struct timeval opStartTime,
4903                    opStopTime;              /* Start/stop times for RPC op*/
4904     struct timeval elapsedTime;             /* Transfer time */
4905
4906     /*
4907      * Set our stats pointer, remember when the RPC operation started, and
4908      * tally the operation.
4909      */
4910     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
4911     FS_LOCK
4912     (opP->numOps)++;
4913     FS_UNLOCK
4914     TM_GetTimeOfDay(&opStartTime, 0);
4915 #endif /* FS_STATS_DETAILED */
4916
4917     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4918         goto Bad_RemoveDir;
4919
4920     code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
4921     
4922 Bad_RemoveDir:
4923     CallPostamble(tcon);
4924
4925 #if FS_STATS_DETAILED
4926     TM_GetTimeOfDay(&opStopTime, 0);
4927     if (code == 0) {
4928       FS_LOCK
4929       (opP->numSuccesses)++;
4930       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4931       fs_stats_AddTo((opP->sumTime), elapsedTime);
4932       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4933       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4934         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4935       }
4936       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4937         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4938       }
4939       FS_UNLOCK
4940     }
4941
4942 #endif /* FS_STATS_DETAILED */
4943
4944     osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4945     return code;
4946
4947 } /*SRXAFS_RemoveDir*/
4948
4949
4950 /*
4951  * This routine is called exclusively by SRXAFS_SetLock(), and should be
4952  * merged into it when possible.
4953  */
4954 static afs_int32
4955 SAFSS_SetLock (struct rx_call *acall,
4956                struct AFSFid *Fid,
4957                ViceLockType type,
4958                struct AFSVolSync *Sync)
4959 {
4960     Vnode * targetptr = 0;              /* vnode of input file */
4961     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4962     int     errorCode = 0;              /* error code */
4963     Volume * volptr = 0;                /* pointer to the volume header */
4964     struct client * client;             /* pointer to client structure */
4965     afs_int32 rights, anyrights;                /* rights for this and any user */
4966     struct client *t_client;            /* tmp ptr to client data */
4967     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4968     static char * locktype[2] = {"LockRead","LockWrite"};
4969     struct rx_connection *tcon = rx_ConnectionOf(acall);
4970
4971     if (type != LockRead && type != LockWrite) {
4972         errorCode = EINVAL;
4973         goto Bad_SetLock;
4974     }
4975     /* Get ptr to client data for user Id for logging */
4976     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4977     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4978     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
4979             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
4980             inet_ntoa(logHostAddr), t_client->ViceId));
4981     FS_LOCK
4982     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
4983     FS_UNLOCK
4984
4985     /*
4986      * Get the vnode and volume for the desired file along with the caller's
4987      * rights to it
4988      */
4989     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
4990                                      DONTCHECK, &parentwhentargetnotdir,
4991                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4992         goto Bad_SetLock;
4993     }
4994
4995     /* set volume synchronization information */
4996     SetVolumeSync(Sync, volptr);
4997
4998     /* Handle the particular type of set locking, type */
4999     errorCode = HandleLocking(targetptr, rights, type);
5000
5001 Bad_SetLock: 
5002     /* Write the all modified vnodes (parent, new files) and volume back */
5003     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5004
5005     if ((errorCode == VREADONLY) && (type == LockRead))
5006        errorCode = 0;  /* allow read locks on RO volumes without saving state */
5007
5008     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
5009     return(errorCode);
5010
5011 }  /*SAFSS_SetLock*/
5012
5013
5014 afs_int32 SRXAFS_OldSetLock(struct rx_call *acall,
5015                             struct AFSFid *Fid,
5016                             ViceLockType type,
5017                             struct AFSVolSync *Sync)
5018 {
5019     return SRXAFS_SetLock(acall, Fid, type, Sync);
5020
5021 } /*SRXAFS_OldSetLock*/
5022
5023
5024 afs_int32 SRXAFS_SetLock (struct rx_call *acall,
5025                           struct AFSFid *Fid,
5026                           ViceLockType type,
5027                           struct AFSVolSync *Sync)
5028 {
5029     afs_int32 code;
5030     struct rx_connection *tcon;
5031 #if FS_STATS_DETAILED
5032     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5033     struct timeval opStartTime,
5034                    opStopTime;              /* Start/stop times for RPC op*/
5035     struct timeval elapsedTime;             /* Transfer time */
5036
5037     /*
5038      * Set our stats pointer, remember when the RPC operation started, and
5039      * tally the operation.
5040      */
5041     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
5042     FS_LOCK
5043     (opP->numOps)++;
5044     FS_UNLOCK
5045     TM_GetTimeOfDay(&opStartTime, 0);
5046 #endif /* FS_STATS_DETAILED */
5047
5048     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5049         goto Bad_SetLock;
5050
5051     code = SAFSS_SetLock (acall, Fid, type, Sync);
5052     
5053 Bad_SetLock:
5054     CallPostamble(tcon);
5055
5056 #if FS_STATS_DETAILED
5057     TM_GetTimeOfDay(&opStopTime, 0); 
5058     if (code == 0) {
5059       FS_LOCK
5060       (opP->numSuccesses)++;
5061       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5062       fs_stats_AddTo((opP->sumTime), elapsedTime);
5063       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5064       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5065         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5066       }
5067       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5068         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5069       }
5070       FS_UNLOCK
5071     }
5072 #endif /* FS_STATS_DETAILED */
5073
5074     osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
5075     return code;
5076
5077 } /*SRXAFS_SetLock*/
5078
5079
5080 /*
5081  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
5082  * merged into it when possible.
5083  */
5084 static afs_int32 
5085 SAFSS_ExtendLock (struct rx_call *acall,
5086                   struct AFSFid *Fid,
5087                   struct AFSVolSync *Sync)
5088
5089 {
5090     Vnode * targetptr = 0;              /* vnode of input file */
5091     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5092     int     errorCode = 0;              /* error code */
5093     Volume * volptr = 0;                /* pointer to the volume header */
5094     struct client * client;             /* pointer to client structure */
5095     afs_int32 rights, anyrights;                /* rights for this and any user */
5096     struct client *t_client;            /* tmp ptr to client data */
5097     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5098     struct rx_connection *tcon = rx_ConnectionOf(acall);
5099
5100     /* Get ptr to client data for user Id for logging */
5101     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5102     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5103     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
5104                Fid->Volume, Fid->Vnode, Fid->Unique, 
5105                inet_ntoa(logHostAddr), t_client->ViceId));
5106     FS_LOCK
5107     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
5108     FS_UNLOCK
5109     /*
5110      * Get the vnode and volume for the desired file along with the caller's
5111      * rights to it
5112      */
5113     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5114                                      DONTCHECK, &parentwhentargetnotdir,
5115                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5116         goto Bad_ExtendLock;
5117     }
5118
5119     /* set volume synchronization information */
5120     SetVolumeSync(Sync, volptr);
5121
5122     /* Handle the actual lock extension */
5123     errorCode = HandleLocking(targetptr, rights, LockExtend);
5124
5125 Bad_ExtendLock: 
5126     /* Put back file's vnode and volume */
5127     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5128
5129     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5130        errorCode = 0;              /* under our generous policy re RO vols */
5131
5132     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
5133     return(errorCode);
5134
5135 } /*SAFSS_ExtendLock*/
5136
5137
5138 afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall,
5139                                 struct AFSFid *Fid,
5140                                 struct AFSVolSync *Sync)
5141 {
5142     return SRXAFS_ExtendLock(acall, Fid, Sync);
5143
5144 } /*SRXAFS_OldExtendLock*/
5145
5146
5147 afs_int32 SRXAFS_ExtendLock (struct rx_call *acall,
5148                              struct AFSFid *Fid,
5149                              struct AFSVolSync *Sync)
5150 {
5151     afs_int32 code;
5152     struct rx_connection *tcon;
5153 #if FS_STATS_DETAILED
5154     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5155     struct timeval opStartTime,
5156                    opStopTime;              /* Start/stop times for RPC op*/
5157     struct timeval elapsedTime;             /* Transfer time */
5158
5159     /*
5160      * Set our stats pointer, remember when the RPC operation started, and
5161      * tally the operation.
5162      */
5163     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
5164     FS_LOCK
5165     (opP->numOps)++;
5166     FS_UNLOCK
5167     TM_GetTimeOfDay(&opStartTime, 0);
5168 #endif /* FS_STATS_DETAILED */
5169
5170     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5171         goto Bad_ExtendLock;
5172
5173     code = SAFSS_ExtendLock (acall, Fid, Sync);
5174
5175 Bad_ExtendLock:
5176     CallPostamble(tcon);
5177
5178 #if FS_STATS_DETAILED
5179     TM_GetTimeOfDay(&opStopTime, 0);
5180     if (code == 0) {
5181       FS_LOCK
5182       (opP->numSuccesses)++;
5183       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5184       fs_stats_AddTo((opP->sumTime), elapsedTime);
5185       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5186       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5187         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5188       }
5189       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5190         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5191       }
5192       FS_UNLOCK
5193     }
5194
5195 #endif /* FS_STATS_DETAILED */
5196
5197     osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
5198     return code;
5199
5200 } /*SRXAFS_ExtendLock*/
5201
5202
5203 /*
5204  * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
5205  * merged into it when possible.
5206  */
5207 static afs_int32 
5208 SAFSS_ReleaseLock (struct rx_call *acall,
5209                    struct AFSFid *Fid,
5210                    struct AFSVolSync *Sync)
5211
5212 {
5213     Vnode * targetptr = 0;              /* vnode of input file */
5214     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5215     int     errorCode = 0;              /* error code */
5216     Volume * volptr = 0;                /* pointer to the volume header */
5217     struct client * client;             /* pointer to client structure */
5218     afs_int32 rights, anyrights;                /* rights for this and any user */
5219     struct client *t_client;            /* tmp ptr to client data */
5220     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5221     struct rx_connection *tcon = rx_ConnectionOf(acall);
5222
5223     /* Get ptr to client data for user Id for logging */
5224     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5225     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5226     ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
5227             Fid->Volume, Fid->Vnode, Fid->Unique,
5228             inet_ntoa(logHostAddr), t_client->ViceId));
5229     FS_LOCK
5230     AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
5231     FS_UNLOCK
5232     /*
5233      * Get the vnode and volume for the desired file along with the caller's
5234      * rights to it
5235      */
5236     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5237                                      DONTCHECK, &parentwhentargetnotdir,
5238                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5239         goto Bad_ReleaseLock;
5240     }
5241
5242     /* set volume synchronization information */
5243     SetVolumeSync(Sync, volptr);
5244
5245     /* Handle the actual lock release */
5246     if ((errorCode = HandleLocking(targetptr, rights, LockRelease)))
5247         goto Bad_ReleaseLock;
5248
5249     /* if no more locks left, a callback would be triggered here */
5250     if (targetptr->disk.lock.lockCount <= 0) {
5251         /* convert the write lock to a read lock before breaking callbacks */
5252         VVnodeWriteToRead(&errorCode, targetptr);
5253         assert(!errorCode || errorCode == VSALVAGE);
5254         BreakCallBack(client->host, Fid, 0);
5255     }
5256
5257 Bad_ReleaseLock: 
5258     /* Put back file's vnode and volume */
5259     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5260
5261     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5262        errorCode = 0;              /* under our generous policy re RO vols */
5263
5264     ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
5265     return(errorCode);
5266
5267 } /*SAFSS_ReleaseLock*/
5268
5269
5270 afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall,
5271                                  struct AFSFid *Fid,
5272                                  struct AFSVolSync *Sync)
5273 {
5274     return SRXAFS_ReleaseLock(acall, Fid, Sync);
5275
5276 } /*SRXAFS_OldReleaseLock*/
5277
5278
5279 afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall,
5280                               struct AFSFid *Fid,
5281                               struct AFSVolSync *Sync)
5282 {
5283     afs_int32 code;
5284     struct rx_connection *tcon;
5285 #if FS_STATS_DETAILED
5286     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5287     struct timeval opStartTime,
5288                    opStopTime;              /* Start/stop times for RPC op*/
5289     struct timeval elapsedTime;             /* Transfer time */
5290
5291     /*
5292      * Set our stats pointer, remember when the RPC operation started, and
5293      * tally the operation.
5294      */
5295     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
5296     FS_LOCK
5297     (opP->numOps)++;
5298     FS_UNLOCK
5299     TM_GetTimeOfDay(&opStartTime, 0);
5300 #endif /* FS_STATS_DETAILED */
5301
5302     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5303         goto Bad_ReleaseLock;
5304
5305     code = SAFSS_ReleaseLock (acall, Fid, Sync);
5306     
5307 Bad_ReleaseLock:
5308     CallPostamble(tcon);
5309
5310 #if FS_STATS_DETAILED
5311     TM_GetTimeOfDay(&opStopTime, 0);
5312     if (code == 0) {
5313       FS_LOCK
5314       (opP->numSuccesses)++;
5315       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5316       fs_stats_AddTo((opP->sumTime), elapsedTime);
5317       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5318       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5319         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5320       }
5321       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5322         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5323       }
5324       FS_UNLOCK
5325     }
5326
5327 #endif /* FS_STATS_DETAILED */
5328
5329     osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
5330     return code;
5331
5332 } /*SRXAFS_ReleaseLock*/
5333
5334
5335 void SetSystemStats(struct AFSStatistics *stats)
5336 {
5337   /* Fix this sometime soon.. */
5338   /* Because hey, it's not like we have a network monitoring protocol... */
5339     struct      timeval time;
5340
5341     /* this works on all system types */
5342     TM_GetTimeOfDay(&time, 0);
5343     stats->CurrentTime = time.tv_sec;
5344 } /*SetSystemStats*/
5345
5346 void SetAFSStats(struct AFSStatistics *stats)
5347 {
5348     extern afs_int32 StartTime, CurrentConnections;
5349     int seconds;
5350
5351     FS_LOCK
5352     stats->CurrentMsgNumber = 0;
5353     stats->OldestMsgNumber = 0;
5354     stats->StartTime = StartTime;
5355     stats->CurrentConnections = CurrentConnections;
5356     stats->TotalAFSCalls = AFSCallStats.TotalCalls;
5357     stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
5358     stats->FetchDatas = AFSCallStats.FetchData;
5359     stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
5360     seconds = AFSCallStats.AccumFetchTime/1000;
5361     if (seconds <= 0) seconds = 1;
5362     stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
5363     stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
5364     stats->StoreDatas = AFSCallStats.StoreData;
5365     stats->StoredBytes = AFSCallStats.TotalStoredBytes;
5366     seconds = AFSCallStats.AccumStoreTime/1000;
5367     if (seconds <= 0) seconds = 1;
5368     stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
5369 #ifdef AFS_NT40_ENV
5370     stats->ProcessSize = -1; /* TODO: */
5371 #else
5372     stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
5373 #endif
5374     FS_UNLOCK
5375     h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
5376             (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
5377
5378 } /*SetAFSStats*/
5379
5380 /* Get disk related information from all AFS partitions. */
5381
5382 void SetVolumeStats(struct AFSStatistics *stats)
5383 {
5384     struct DiskPartition * part;
5385     int i = 0;
5386
5387     for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
5388         stats->Disks[i].TotalBlocks = part->totalUsable;
5389         stats->Disks[i].BlocksAvailable = part->free;
5390         memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
5391         strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
5392         i++;
5393     }
5394     while (i < AFS_MSTATDISKS) {
5395         stats->Disks[i].TotalBlocks = -1;
5396         i++;
5397     }
5398 } /*SetVolumeStats*/
5399
5400 afs_int32 SRXAFS_GetStatistics (struct rx_call *acall,
5401                                 struct ViceStatistics *Statistics)
5402 {
5403     afs_int32 code;
5404     struct rx_connection *tcon;
5405 #if FS_STATS_DETAILED
5406     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5407     struct timeval opStartTime,
5408                    opStopTime;              /* Start/stop times for RPC op*/
5409     struct timeval elapsedTime;             /* Transfer time */
5410
5411     /*
5412      * Set our stats pointer, remember when the RPC operation started, and
5413      * tally the operation.
5414      */
5415     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
5416     FS_LOCK
5417     (opP->numOps)++;
5418     FS_UNLOCK
5419     TM_GetTimeOfDay(&opStartTime, 0);
5420 #endif /* FS_STATS_DETAILED */
5421
5422     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
5423         goto Bad_GetStatistics;
5424
5425     ViceLog(1, ("SAFS_GetStatistics Received\n"));
5426     FS_LOCK
5427     AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
5428     FS_UNLOCK
5429     memset(Statistics, 0, sizeof(*Statistics));
5430     SetAFSStats((struct AFSStatistics *)Statistics);
5431     SetVolumeStats((struct AFSStatistics *)Statistics);
5432     SetSystemStats((struct AFSStatistics *)Statistics);
5433     
5434 Bad_GetStatistics:
5435     CallPostamble(tcon);
5436
5437 #if FS_STATS_DETAILED
5438     TM_GetTimeOfDay(&opStopTime, 0);
5439     if (code == 0) {
5440       FS_LOCK
5441       (opP->numSuccesses)++;
5442       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5443       fs_stats_AddTo((opP->sumTime), elapsedTime);
5444       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5445       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5446         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5447       }
5448       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5449         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5450       }
5451       FS_UNLOCK
5452     }
5453 #endif /* FS_STATS_DETAILED */
5454
5455     return code;
5456
5457 } /*SRXAFS_GetStatistics*/
5458
5459
5460 /*------------------------------------------------------------------------
5461  * EXPORTED SRXAFS_XStatsVersion
5462  *
5463  * Description:
5464  *      Routine called by the server-side RPC interface to implement
5465  *      pulling out the xstat version number for the File Server.
5466  *
5467  * Arguments:
5468  *      a_versionP : Ptr to the version number variable to set.
5469  *
5470  * Returns:
5471  *      0 (always)
5472  *
5473  * Environment:
5474  *      Nothing interesting.
5475  *
5476  * Side Effects:
5477  *      As advertised.
5478  *------------------------------------------------------------------------*/
5479
5480 afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
5481 { /*SRXAFS_XStatsVersion*/
5482
5483 #if FS_STATS_DETAILED
5484     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5485     struct timeval opStartTime,
5486                    opStopTime;              /* Start/stop times for RPC op*/
5487     struct timeval elapsedTime;             /* Transfer time */
5488
5489     /*
5490      * Set our stats pointer, remember when the RPC operation started, and
5491      * tally the operation.
5492      */
5493     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
5494     FS_LOCK
5495     (opP->numOps)++;
5496     FS_UNLOCK
5497     TM_GetTimeOfDay(&opStartTime, 0);
5498 #endif /* FS_STATS_DETAILED */
5499
5500     *a_versionP = AFS_XSTAT_VERSION;
5501
5502 #if FS_STATS_DETAILED
5503     TM_GetTimeOfDay(&opStopTime, 0);
5504     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5505     fs_stats_AddTo((opP->sumTime), elapsedTime);
5506     fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5507     if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5508         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5509     }
5510     if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5511         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5512     }
5513     FS_LOCK
5514     (opP->numSuccesses)++;
5515     FS_UNLOCK
5516 #endif /* FS_STATS_DETAILED */
5517
5518     return(0);
5519
5520 }  /*SRXAFS_XStatsVersion*/
5521
5522
5523 /*------------------------------------------------------------------------
5524  * PRIVATE FillPerfValues
5525  *
5526  * Description:
5527  *      Routine called to fill a regular performance data structure.
5528  *
5529  * Arguments:
5530  *      a_perfP : Ptr to perf structure to fill
5531  *
5532  * Returns:
5533  *      Nothing.
5534  *
5535  * Environment:
5536  *      Various collections need this info, so the guts were put in
5537  *      this separate routine.
5538  *
5539  * Side Effects:
5540  *      As advertised.
5541  *------------------------------------------------------------------------*/
5542
5543 static void FillPerfValues(struct afs_PerfStats *a_perfP)
5544 { /*FillPerfValues*/
5545
5546     int dir_Buffers;            /*# buffers in use by dir package*/
5547     int dir_Calls;              /*# read calls in dir package*/
5548     int dir_IOs;                /*# I/O ops in dir package*/
5549
5550     /*
5551      * Vnode cache section.
5552      */
5553     a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
5554     a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
5555     a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
5556     a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
5557     a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
5558     a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
5559     a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
5560     a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
5561     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
5562     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
5563     a_perfP->vcache_H_Entries = VolumeCacheSize;
5564     a_perfP->vcache_H_Gets = VolumeGets;
5565     a_perfP->vcache_H_Replacements = VolumeReplacements;
5566     
5567     /*
5568      * Directory section.
5569      */
5570     DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
5571     a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
5572     a_perfP->dir_Calls = (afs_int32 )dir_Calls;
5573     a_perfP->dir_IOs = (afs_int32) dir_IOs;
5574     
5575     /*
5576      * Rx section.
5577      */
5578     a_perfP->rx_packetRequests =
5579         (afs_int32) rx_stats.packetRequests;
5580     a_perfP->rx_noPackets_RcvClass =
5581         (afs_int32) rx_stats.receivePktAllocFailures;
5582     a_perfP->rx_noPackets_SendClass =
5583         (afs_int32) rx_stats.sendPktAllocFailures;
5584     a_perfP->rx_noPackets_SpecialClass =
5585         (afs_int32) rx_stats.specialPktAllocFailures;
5586     a_perfP->rx_socketGreedy =
5587         (afs_int32) rx_stats.socketGreedy;
5588     a_perfP->rx_bogusPacketOnRead =
5589         (afs_int32) rx_stats.bogusPacketOnRead;
5590     a_perfP->rx_bogusHost =
5591         (afs_int32) rx_stats.bogusHost;
5592     a_perfP->rx_noPacketOnRead =
5593         (afs_int32) rx_stats.noPacketOnRead;
5594     a_perfP->rx_noPacketBuffersOnRead =
5595         (afs_int32) rx_stats.noPacketBuffersOnRead;
5596     a_perfP->rx_selects =
5597         (afs_int32) rx_stats.selects;
5598     a_perfP->rx_sendSelects =
5599         (afs_int32) rx_stats.sendSelects;
5600     a_perfP->rx_packetsRead_RcvClass =
5601         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
5602     a_perfP->rx_packetsRead_SendClass =
5603         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
5604     a_perfP->rx_packetsRead_SpecialClass =
5605         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
5606     a_perfP->rx_dataPacketsRead =
5607         (afs_int32) rx_stats.dataPacketsRead;
5608     a_perfP->rx_ackPacketsRead =
5609         (afs_int32) rx_stats.ackPacketsRead;
5610     a_perfP->rx_dupPacketsRead =
5611         (afs_int32) rx_stats.dupPacketsRead;
5612     a_perfP->rx_spuriousPacketsRead =
5613         (afs_int32) rx_stats.spuriousPacketsRead;
5614     a_perfP->rx_packetsSent_RcvClass =
5615         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
5616     a_perfP->rx_packetsSent_SendClass =
5617         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
5618     a_perfP->rx_packetsSent_SpecialClass =
5619         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
5620     a_perfP->rx_ackPacketsSent =
5621         (afs_int32) rx_stats.ackPacketsSent;
5622     a_perfP->rx_pingPacketsSent =
5623         (afs_int32) rx_stats.pingPacketsSent;
5624     a_perfP->rx_abortPacketsSent =
5625         (afs_int32) rx_stats.abortPacketsSent;
5626     a_perfP->rx_busyPacketsSent =
5627         (afs_int32) rx_stats.busyPacketsSent;
5628     a_perfP->rx_dataPacketsSent =
5629         (afs_int32) rx_stats.dataPacketsSent;
5630     a_perfP->rx_dataPacketsReSent =
5631         (afs_int32) rx_stats.dataPacketsReSent;
5632     a_perfP->rx_dataPacketsPushed =
5633         (afs_int32) rx_stats.dataPacketsPushed;
5634     a_perfP->rx_ignoreAckedPacket =
5635         (afs_int32) rx_stats.ignoreAckedPacket;
5636     a_perfP->rx_totalRtt_Sec =
5637         (afs_int32) rx_stats.totalRtt.sec;
5638     a_perfP->rx_totalRtt_Usec =
5639         (afs_int32) rx_stats.totalRtt.usec;
5640     a_perfP->rx_minRtt_Sec =
5641         (afs_int32) rx_stats.minRtt.sec;
5642     a_perfP->rx_minRtt_Usec =
5643         (afs_int32) rx_stats.minRtt.usec;
5644     a_perfP->rx_maxRtt_Sec =
5645         (afs_int32) rx_stats.maxRtt.sec;
5646     a_perfP->rx_maxRtt_Usec =
5647         (afs_int32) rx_stats.maxRtt.usec;
5648     a_perfP->rx_nRttSamples =
5649         (afs_int32) rx_stats.nRttSamples;
5650     a_perfP->rx_nServerConns =
5651         (afs_int32) rx_stats.nServerConns;
5652     a_perfP->rx_nClientConns =
5653         (afs_int32) rx_stats.nClientConns;
5654     a_perfP->rx_nPeerStructs =
5655         (afs_int32) rx_stats.nPeerStructs;
5656     a_perfP->rx_nCallStructs =
5657         (afs_int32) rx_stats.nCallStructs;
5658     a_perfP->rx_nFreeCallStructs =
5659         (afs_int32) rx_stats.nFreeCallStructs;
5660     
5661     a_perfP->host_NumHostEntries = HTs;
5662     a_perfP->host_HostBlocks = HTBlocks;
5663     h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
5664                       &(a_perfP->host_HostsInSameNetOrSubnet),
5665                       &(a_perfP->host_HostsInDiffSubnet),
5666                       &(a_perfP->host_HostsInDiffNetwork));
5667     a_perfP->host_NumClients = CEs;
5668     a_perfP->host_ClientBlocks = CEBlocks;
5669     
5670     a_perfP->sysname_ID = afs_perfstats.sysname_ID;
5671
5672 } /*FillPerfValues*/
5673
5674
5675 /*------------------------------------------------------------------------
5676  * EXPORTED SRXAFS_GetXStats
5677  *
5678  * Description:
5679  *      Routine called by the server-side callback RPC interface to
5680  *      implement getting the given data collection from the extended
5681  *      File Server statistics.
5682  *
5683  * Arguments:
5684  *      a_call              : Ptr to Rx call on which this request came in.
5685  *      a_clientVersionNum  : Client version number.
5686  *      a_opCode            : Desired operation.
5687  *      a_serverVersionNumP : Ptr to version number to set.
5688  *      a_timeP             : Ptr to time value (seconds) to set.
5689  *      a_dataP             : Ptr to variable array structure to return
5690  *                            stuff in.
5691  *
5692  * Returns:
5693  *      0 (always).
5694  *
5695  * Environment:
5696  *      Nothing interesting.
5697  *
5698  * Side Effects:
5699  *      As advertised.
5700  *------------------------------------------------------------------------*/
5701
5702 afs_int32 SRXAFS_GetXStats(struct rx_call *a_call,
5703                            afs_int32 a_clientVersionNum,
5704                            afs_int32 a_collectionNumber,
5705                            afs_int32 *a_srvVersionNumP,
5706                            afs_int32 *a_timeP,
5707                            AFS_CollData *a_dataP)
5708 { /*SRXAFS_GetXStats*/
5709
5710     register int code;          /*Return value*/
5711     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
5712     afs_int32 dataBytes;                /*Bytes in data buffer*/
5713 #if FS_STATS_DETAILED
5714     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5715     struct timeval opStartTime,
5716                    opStopTime;              /* Start/stop times for RPC op*/
5717     struct timeval elapsedTime;             /* Transfer time */
5718
5719     /*
5720      * Set our stats pointer, remember when the RPC operation started, and
5721      * tally the operation.
5722      */
5723     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
5724     FS_LOCK
5725     (opP->numOps)++;
5726     FS_UNLOCK
5727     TM_GetTimeOfDay(&opStartTime, 0);
5728 #endif /* FS_STATS_DETAILED */
5729
5730     /*
5731      * Record the time of day and the server version number.
5732      */
5733     *a_srvVersionNumP = AFS_XSTAT_VERSION;
5734     *a_timeP = FT_ApproxTime();
5735
5736     /*
5737      * Stuff the appropriate data in there (assume victory)
5738      */
5739     code = 0;
5740
5741     ViceLog(1, ("Received GetXStats call for collection %d\n",  a_collectionNumber));
5742
5743 #if 0
5744     /*
5745      * We're not keeping stats, so just return successfully with
5746      * no data.
5747      */
5748     a_dataP->AFS_CollData_len = 0;
5749     a_dataP->AFS_CollData_val = NULL;
5750 #endif /* 0 */
5751
5752     switch(a_collectionNumber) {
5753       case AFS_XSTATSCOLL_CALL_INFO:
5754         /*
5755          * Pass back all the call-count-related data.
5756          *
5757          * >>> We are forced to allocate a separate area in which to
5758          * >>> put this stuff in by the RPC stub generator, since it
5759          * >>> will be freed at the tail end of the server stub code.
5760          */
5761 #if 0
5762         /*
5763          * I don't think call-level stats are being collected yet
5764          * for the File Server.
5765          */
5766         dataBytes = sizeof(struct afs_Stats);
5767         dataBuffP = (afs_int32 *)malloc(dataBytes);
5768         memcpy(dataBuffP, &afs_cmstats, dataBytes);
5769         a_dataP->AFS_CollData_len = dataBytes>>2;
5770         a_dataP->AFS_CollData_val = dataBuffP;
5771 #else
5772         a_dataP->AFS_CollData_len = 0;
5773         a_dataP->AFS_CollData_val = NULL;
5774 #endif /* 0 */
5775         break;
5776
5777       case AFS_XSTATSCOLL_PERF_INFO:
5778         /*
5779          * Pass back all the regular performance-related data.
5780          *
5781          * >>> We are forced to allocate a separate area in which to
5782          * >>> put this stuff in by the RPC stub generator, since it
5783          * >>> will be freed at the tail end of the server stub code.
5784          */
5785
5786         afs_perfstats.numPerfCalls++;
5787         FillPerfValues(&afs_perfstats);
5788
5789         /*
5790          * Don't overwrite the spares at the end.
5791          */
5792
5793         dataBytes = sizeof(struct afs_PerfStats);
5794         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5795         memcpy(dataBuffP, &afs_perfstats, dataBytes);
5796         a_dataP->AFS_CollData_len = dataBytes>>2;
5797         a_dataP->AFS_CollData_val = dataBuffP;
5798         break;
5799
5800       case AFS_XSTATSCOLL_FULL_PERF_INFO:
5801         /*
5802          * Pass back the full collection of performance-related data.
5803          * We have to stuff the basic, overall numbers in, but the
5804          * detailed numbers are kept in the structure already.
5805          *
5806          * >>> We are forced to allocate a separate area in which to
5807          * >>> put this stuff in by the RPC stub generator, since it
5808          * >>> will be freed at the tail end of the server stub code.
5809          */
5810
5811         afs_perfstats.numPerfCalls++;
5812 #if FS_STATS_DETAILED
5813         afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
5814         FillPerfValues(&afs_FullPerfStats.overall);
5815
5816         /*
5817          * Don't overwrite the spares at the end.
5818          */
5819
5820         dataBytes = sizeof(struct fs_stats_FullPerfStats);
5821         dataBuffP = (afs_int32 *)osi_Alloc(dataBytes);
5822         memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
5823         a_dataP->AFS_CollData_len = dataBytes>>2;
5824         a_dataP->AFS_CollData_val = dataBuffP;
5825 #endif
5826         break;
5827
5828       default:
5829         /*
5830          * Illegal collection number.
5831          */
5832         a_dataP->AFS_CollData_len = 0;
5833         a_dataP->AFS_CollData_val = NULL;
5834         code = 1;
5835     } /*Switch on collection number*/
5836
5837 #if FS_STATS_DETAILED
5838     TM_GetTimeOfDay(&opStopTime, 0);
5839     if (code == 0) {
5840       FS_LOCK
5841       (opP->numSuccesses)++;
5842       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5843       fs_stats_AddTo((opP->sumTime), elapsedTime);
5844       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5845       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5846         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5847       }
5848       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5849         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5850       }
5851       FS_UNLOCK
5852     }
5853
5854 #endif /* FS_STATS_DETAILED */
5855
5856     return(code);
5857
5858 } /*SRXAFS_GetXStats*/
5859
5860
5861 afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall,
5862                                   struct AFSCBFids *FidArray,
5863                                   struct AFSCBs *CallBackArray)
5864 {
5865     afs_int32 errorCode;
5866     register int i;
5867     struct client *client;
5868     struct rx_connection *tcon;
5869 #if FS_STATS_DETAILED
5870     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5871     struct timeval opStartTime,
5872                    opStopTime;              /* Start/stop times for RPC op*/
5873     struct timeval elapsedTime;             /* Transfer time */
5874
5875     /*
5876      * Set our stats pointer, remember when the RPC operation started, and
5877      * tally the operation.
5878      */
5879     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
5880     FS_LOCK
5881     (opP->numOps)++;
5882     FS_UNLOCK
5883     TM_GetTimeOfDay(&opStartTime, 0);
5884 #endif /* FS_STATS_DETAILED */
5885
5886     ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
5887     FS_LOCK
5888     AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
5889     FS_UNLOCK
5890     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
5891         goto Bad_GiveUpCallBacks;
5892
5893     if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
5894        ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", 
5895                    FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, 
5896                    (tcon->peer ? tcon->peer->host : 0)));
5897        errorCode = EINVAL;
5898        goto Bad_GiveUpCallBacks;
5899     }
5900
5901     errorCode = GetClient(tcon, &client);
5902     if (!errorCode) {
5903        for (i=0; i < FidArray->AFSCBFids_len; i++) {
5904           register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
5905           DeleteCallBack(client->host, fid);
5906        }
5907     }
5908
5909 Bad_GiveUpCallBacks:
5910     CallPostamble(tcon);
5911
5912 #if FS_STATS_DETAILED
5913     TM_GetTimeOfDay(&opStopTime, 0);
5914     if (errorCode == 0) {
5915       FS_LOCK
5916       (opP->numSuccesses)++;
5917       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5918       fs_stats_AddTo((opP->sumTime), elapsedTime);
5919       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5920       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5921         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5922       }
5923       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5924         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5925       }
5926       FS_UNLOCK
5927     }
5928 #endif /* FS_STATS_DETAILED */
5929 out:
5930     return errorCode;
5931
5932 } /*SRXAFS_GiveUpCallBacks*/
5933
5934
5935 afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall,
5936                                  char *avolid,
5937                                  struct AFSVolumeInfo *avolinfo)
5938 {
5939     return(VNOVOL);             /* XXX Obsolete routine XXX */
5940
5941 } /*SRXAFS_NGetVolumeInfo*/
5942
5943
5944 /*
5945  * Dummy routine. Should never be called (the cache manager should only 
5946  * invoke this interface when communicating with a AFS/DFS Protocol
5947  * Translator).
5948  */
5949 afs_int32 SRXAFS_Lookup(struct rx_call *call_p,
5950                         struct AFSFid *afs_dfid_p,
5951                         char *afs_name_p,
5952                         struct AFSFid *afs_fid_p,
5953                         struct AFSFetchStatus *afs_status_p,
5954                         struct AFSFetchStatus *afs_dir_status_p,
5955                         struct AFSCallBack *afs_callback_p,
5956                         struct AFSVolSync *afs_sync_p)
5957 {
5958     return EINVAL;
5959 }
5960
5961
5962 afs_int32 SRXAFS_FlushCPS(struct rx_call *acall,
5963                           struct ViceIds *vids,
5964                           struct IPAddrs *addrs,
5965                           afs_int32 spare1,
5966                           afs_int32 *spare2, 
5967                           afs_int32 *spare3)
5968 {
5969     int i;
5970     afs_int32 nids, naddrs;
5971     afs_int32 *vd, *addr;
5972     int     errorCode = 0;              /* return code to caller */
5973     struct client *client;
5974     struct rx_connection *tcon = rx_ConnectionOf(acall);
5975
5976     ViceLog(1, ("SRXAFS_FlushCPS\n"));
5977     FS_LOCK
5978     AFSCallStats.TotalCalls++;
5979     FS_UNLOCK
5980     nids = vids->ViceIds_len;   /* # of users in here */
5981     naddrs = addrs->IPAddrs_len;        /* # of hosts in here */
5982     if (nids < 0 || naddrs < 0) {
5983         errorCode = EINVAL;
5984         goto Bad_FlushCPS;
5985     }
5986
5987     vd = vids->ViceIds_val;
5988     for (i=0; i<nids; i++, vd++) {
5989       if (!*vd)
5990         continue;
5991       client = h_ID2Client(*vd);  /* returns client locked, or NULL */
5992       if (!client)
5993         continue;
5994
5995       BoostSharedLock(&client->lock);
5996       client->prfail = 2;       /* Means re-eval client's cps */
5997 #ifdef  notdef
5998       if (client->tcon) {
5999         rx_SetRock(((struct rx_connection *) client->tcon), 0);
6000       }
6001 #endif
6002       if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
6003         free(client->CPS.prlist_val);
6004         client->CPS.prlist_val = NULL;
6005         client->CPS.prlist_len = 0;
6006       }
6007       ReleaseWriteLock(&client->lock);
6008     }
6009
6010     addr = addrs->IPAddrs_val;
6011     for (i=0; i<naddrs; i++, addr++) {
6012       if (*addr)
6013         h_flushhostcps(*addr, 7001);
6014     }
6015
6016 Bad_FlushCPS:
6017     ViceLog(2, ("SAFS_FlushCPS  returns %d\n", errorCode)); 
6018     return errorCode;
6019 } /*SRXAFS_FlushCPS */
6020
6021 /* worthless hack to let CS keep running ancient software */
6022 static int afs_vtoi(register char *aname)
6023 {
6024     register afs_int32 temp;
6025     register int tc;
6026
6027     temp = 0;
6028     while((tc = *aname++)) {
6029         if (tc > '9' || tc < '0') return 0; /* invalid name */
6030         temp *= 10;
6031         temp += tc - '0';
6032     }
6033     return temp;
6034 }
6035
6036 /*
6037  * may get name or #, but must handle all weird cases (recognize readonly
6038  * or backup volumes by name or #
6039  */
6040 static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave,
6041                                  register struct VolumeInfo *av)
6042 {
6043     register int i, j, vol;
6044     afs_int32 mask, whichType;
6045     afs_uint32 *serverHost, *typePtr;
6046     
6047     /* figure out what type we want if by name */
6048     i = strlen(aname);
6049     if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
6050         whichType = BACKVOL;
6051     else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
6052         whichType = ROVOL;
6053     else whichType = RWVOL;
6054     
6055     vol = afs_vtoi(aname);
6056     if (vol == 0) vol = ave->volumeId[whichType];
6057     
6058     /*
6059      * Now vol has volume # we're interested in.  Next, figure out the type
6060      * of the volume by looking finding it in the vldb entry
6061      */
6062     if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
6063         mask = VLSF_RWVOL;
6064         whichType = RWVOL;
6065     }
6066     else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
6067         mask = VLSF_ROVOL;
6068         whichType = ROVOL;
6069     }
6070     else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
6071         mask = VLSF_RWVOL;  /* backup always is on the same volume as parent */
6072         whichType = BACKVOL;
6073     }
6074     else
6075         return  EINVAL;     /* error: can't find volume in vldb entry */
6076     
6077     typePtr = &av->Type0;
6078     serverHost = &av->Server0;
6079     av->Vid = vol;
6080     av->Type = whichType;
6081     av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
6082     if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
6083     if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
6084     if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
6085
6086     for(i=0,j=0; i<ave->nServers; i++) {
6087         if ((ave->serverFlags[i] & mask) == 0) continue;    /* wrong volume */
6088         serverHost[j] = ave->serverNumber[i];
6089         j++;
6090     }
6091     av->ServerCount = j;
6092     if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
6093     return 0;
6094 }
6095
6096 static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo)
6097 {
6098     static struct rx_connection *vlConn = 0;
6099     static int down = 0;
6100     static afs_int32 lastDownTime = 0;
6101     struct vldbentry tve;
6102     struct rx_securityClass *vlSec;
6103     register afs_int32 code;
6104
6105     if (!vlConn) {
6106         vlSec = rxnull_NewClientSecurityObject();
6107         vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
6108         rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
6109     }
6110     if (down && (FT_ApproxTime() < lastDownTime + 180)) {
6111         return 1;   /* failure */
6112     }
6113
6114     code = VL_GetEntryByNameO(vlConn, avolid, &tve);
6115     if (code >= 0) down = 0;    /* call worked */
6116     if (code) {
6117         if (code < 0) {
6118             lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
6119             down = 1;
6120         }
6121         return code;
6122     }
6123
6124     /* otherwise convert to old format vldb entry */
6125     code = CopyVolumeEntry(avolid, &tve, avolinfo);
6126     return code;
6127 }
6128
6129
6130
6131
6132
6133
6134 afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall,
6135                                 char *avolid,
6136                                 struct VolumeInfo *avolinfo)
6137 {
6138     afs_int32 code;
6139     struct rx_connection *tcon;
6140 #if FS_STATS_DETAILED
6141     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6142     struct timeval opStartTime,
6143                    opStopTime;              /* Start/stop times for RPC op*/
6144     struct timeval elapsedTime;             /* Transfer time */
6145
6146     /*
6147      * Set our stats pointer, remember when the RPC operation started, and
6148      * tally the operation.
6149      */
6150     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
6151     FS_LOCK
6152     (opP->numOps)++;
6153     FS_UNLOCK
6154     TM_GetTimeOfDay(&opStartTime, 0);
6155 #endif /* FS_STATS_DETAILED */
6156     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6157         goto Bad_GetVolumeInfo;
6158
6159     FS_LOCK
6160     AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
6161     FS_UNLOCK
6162
6163     code = TryLocalVLServer(avolid, avolinfo);
6164     ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
6165                 code, avolinfo->Vid, avolinfo->Type,
6166                 avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
6167                 avolinfo->Server3));
6168     avolinfo->Type4     = 0xabcd9999;   /* tell us to try new vldb */
6169
6170 Bad_GetVolumeInfo:
6171     CallPostamble(tcon);
6172
6173 #if FS_STATS_DETAILED
6174     TM_GetTimeOfDay(&opStopTime, 0);
6175     if (code == 0) {
6176       FS_LOCK
6177       (opP->numSuccesses)++;
6178       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6179       fs_stats_AddTo((opP->sumTime), elapsedTime);
6180       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6181       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6182         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6183       }
6184       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6185         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6186       }
6187       FS_UNLOCK
6188     }
6189
6190 #endif /* FS_STATS_DETAILED */
6191
6192     return code;
6193
6194 } /*SRXAFS_GetVolumeInfo*/
6195
6196
6197 afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall,
6198                                  afs_int32 avolid,
6199                                  AFSFetchVolumeStatus *FetchVolStatus,
6200                                  char **Name,
6201                                  char **OfflineMsg,
6202                                  char **Motd)
6203 {
6204     Vnode * targetptr = 0;              /* vnode of the new file */
6205     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6206     int     errorCode = 0;              /* error code */
6207     Volume * volptr = 0;                /* pointer to the volume header */
6208     struct client * client;             /* pointer to client entry */
6209     afs_int32 rights, anyrights;                /* rights for this and any user */
6210     AFSFid  dummyFid;
6211     struct rx_connection *tcon;
6212 #if FS_STATS_DETAILED
6213     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6214     struct timeval opStartTime,
6215                    opStopTime;              /* Start/stop times for RPC op*/
6216     struct timeval elapsedTime;             /* Transfer time */
6217
6218     /*
6219      * Set our stats pointer, remember when the RPC operation started, and
6220      * tally the operation.
6221      */
6222     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
6223     FS_LOCK
6224     (opP->numOps)++;
6225     FS_UNLOCK
6226     TM_GetTimeOfDay(&opStartTime, 0);
6227 #endif /* FS_STATS_DETAILED */
6228
6229     ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
6230     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6231         goto Bad_GetVolumeStatus;
6232
6233     FS_LOCK
6234     AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
6235     FS_UNLOCK
6236
6237     if (avolid == 0) {
6238         errorCode = EINVAL;
6239         goto Bad_GetVolumeStatus;
6240     }
6241     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6242
6243     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6244                                      MustBeDIR, &parentwhentargetnotdir,
6245                                      &client, READ_LOCK, &rights, &anyrights)))
6246         goto Bad_GetVolumeStatus;
6247
6248     if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
6249         errorCode = EACCES;
6250         goto Bad_GetVolumeStatus;
6251     }
6252     RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
6253
6254 Bad_GetVolumeStatus:
6255     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6256     ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
6257     /* next is to guarantee out strings exist for stub */
6258     if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
6259     if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
6260     if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
6261     CallPostamble(tcon);
6262
6263 #if FS_STATS_DETAILED
6264     TM_GetTimeOfDay(&opStopTime, 0);
6265     if (errorCode == 0) {
6266       FS_LOCK
6267       (opP->numSuccesses)++;
6268       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6269       fs_stats_AddTo((opP->sumTime), elapsedTime);
6270       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6271       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6272         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6273       }
6274       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6275         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6276       }
6277       FS_UNLOCK
6278     }
6279
6280 #endif /* FS_STATS_DETAILED */
6281     return(errorCode);
6282
6283 } /*SRXAFS_GetVolumeStatus*/
6284
6285
6286 afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall,
6287                                   afs_int32 avolid,
6288                                   AFSStoreVolumeStatus *StoreVolStatus,
6289                                   char *Name,
6290                                   char *OfflineMsg,
6291                                   char *Motd)
6292 {
6293     Vnode * targetptr = 0;              /* vnode of the new file */
6294     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6295     int     errorCode = 0;              /* error code */
6296     Volume * volptr = 0;                /* pointer to the volume header */
6297     struct client * client;             /* pointer to client entry */
6298     afs_int32 rights, anyrights;                /* rights for this and any user */
6299     AFSFid  dummyFid;
6300     struct rx_connection *tcon = rx_ConnectionOf(acall);
6301 #if FS_STATS_DETAILED
6302     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6303     struct timeval opStartTime,
6304                    opStopTime;              /* Start/stop times for RPC op*/
6305     struct timeval elapsedTime;             /* Transfer time */
6306
6307     /*
6308      * Set our stats pointer, remember when the RPC operation started, and
6309      * tally the operation.
6310      */
6311     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
6312     FS_LOCK
6313     (opP->numOps)++;
6314     FS_UNLOCK
6315     TM_GetTimeOfDay(&opStartTime, 0);
6316 #endif /* FS_STATS_DETAILED */
6317
6318     ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
6319     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6320         goto Bad_SetVolumeStatus;
6321
6322     FS_LOCK
6323     AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
6324     FS_UNLOCK
6325
6326     if (avolid == 0) {
6327         errorCode = EINVAL;
6328         goto Bad_SetVolumeStatus;
6329     }
6330     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6331
6332     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6333                                      MustBeDIR, &parentwhentargetnotdir,
6334                                      &client, READ_LOCK, &rights, &anyrights)))
6335         goto Bad_SetVolumeStatus;
6336
6337     if (readonlyServer) {
6338         errorCode = VREADONLY;
6339         goto Bad_SetVolumeStatus;
6340     }
6341     if (VanillaUser(client)) {
6342         errorCode = EACCES;
6343         goto Bad_SetVolumeStatus;
6344     }
6345
6346     errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
6347                                       OfflineMsg, Motd);
6348
6349  Bad_SetVolumeStatus:
6350     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6351     ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
6352     CallPostamble(tcon);
6353
6354 #if FS_STATS_DETAILED
6355     TM_GetTimeOfDay(&opStopTime, 0);
6356     if (errorCode == 0) {
6357       FS_LOCK
6358       (opP->numSuccesses)++;
6359       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6360       fs_stats_AddTo((opP->sumTime), elapsedTime);
6361       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6362       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6363         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6364       }
6365       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6366         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6367       }
6368       FS_UNLOCK
6369     }
6370
6371 #endif /* FS_STATS_DETAILED */
6372
6373     osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
6374     return(errorCode);
6375
6376 } /*SRXAFS_SetVolumeStatus*/
6377
6378 #define DEFAULTVOLUME   "root.afs"
6379
6380 afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName)
6381 {
6382     int fd;
6383     int len;
6384     char *temp;
6385     int errorCode = 0;          /* error code */
6386     struct rx_connection *tcon;
6387 #if FS_STATS_DETAILED
6388     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6389     struct timeval opStartTime,
6390                    opStopTime;              /* Start/stop times for RPC op*/
6391     struct timeval elapsedTime;             /* Transfer time */
6392
6393     /*
6394      * Set our stats pointer, remember when the RPC operation started, and
6395      * tally the operation.
6396      */
6397     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
6398     FS_LOCK
6399     (opP->numOps)++;
6400     FS_UNLOCK
6401     TM_GetTimeOfDay(&opStartTime, 0);
6402 #endif /* FS_STATS_DETAILED */
6403
6404     return FSERR_EOPNOTSUPP;
6405
6406 #ifdef  notdef
6407     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
6408         goto Bad_GetRootVolume;
6409     FS_LOCK
6410     AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
6411     FS_UNLOCK
6412
6413     temp = malloc(256);
6414     fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
6415     if (fd <= 0)
6416         strcpy(temp, DEFAULTVOLUME);
6417     else {
6418 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6419         lockf(fd, F_LOCK, 0);
6420 #else
6421         flock(fd, LOCK_EX);
6422 #endif
6423         len = read(fd, temp, 256);
6424 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6425         lockf(fd, F_ULOCK, 0);
6426 #else
6427         flock(fd, LOCK_UN);
6428 #endif
6429         close(fd);
6430         if (temp[len-1] == '\n') len--;
6431         temp[len] = '\0';
6432     }
6433     *VolumeName = temp;     /* freed by rx server-side stub */
6434
6435 Bad_GetRootVolume:
6436     CallPostamble(tcon);
6437
6438 #if FS_STATS_DETAILED
6439     TM_GetTimeOfDay(&opStopTime, 0);
6440     if (errorCode == 0) {
6441       FS_LOCK
6442       (opP->numSuccesses)++;
6443       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6444       fs_stats_AddTo((opP->sumTime), elapsedTime);
6445       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6446       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6447         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6448       }
6449       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6450         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6451       }
6452       FS_UNLOCK
6453     }
6454 #endif /* FS_STATS_DETAILED */
6455
6456     return(errorCode);
6457 #endif  /* notdef */
6458
6459 } /*SRXAFS_GetRootVolume*/
6460
6461
6462 /* still works because a struct CBS is the same as a struct AFSOpaque */
6463 afs_int32 SRXAFS_CheckToken (struct rx_call *acall,
6464                              afs_int32 AfsId,
6465                              struct AFSOpaque *Token)
6466 {
6467     afs_int32 code;
6468     struct rx_connection *tcon;
6469 #if FS_STATS_DETAILED
6470     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6471     struct timeval opStartTime,
6472                    opStopTime;              /* Start/stop times for RPC op*/
6473     struct timeval elapsedTime;             /* Transfer time */
6474
6475     /*
6476      * Set our stats pointer, remember when the RPC operation started, and
6477      * tally the operation.
6478      */
6479     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
6480     FS_LOCK
6481     (opP->numOps)++;
6482     FS_UNLOCK
6483     TM_GetTimeOfDay(&opStartTime, 0);
6484 #endif /* FS_STATS_DETAILED */
6485
6486     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6487         goto Bad_CheckToken;
6488
6489     code = FSERR_ECONNREFUSED;
6490     
6491 Bad_CheckToken:
6492     CallPostamble(tcon);
6493
6494 #if FS_STATS_DETAILED
6495     TM_GetTimeOfDay(&opStopTime, 0);
6496     if (code == 0) {
6497       FS_LOCK
6498       (opP->numSuccesses)++;
6499       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6500       fs_stats_AddTo((opP->sumTime), elapsedTime);
6501       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6502       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6503         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6504       }
6505       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6506         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6507       }
6508       FS_UNLOCK
6509     }
6510
6511 #endif /* FS_STATS_DETAILED */
6512
6513     return code;
6514
6515 } /*SRXAFS_CheckToken*/
6516
6517 afs_int32 SRXAFS_GetTime (struct rx_call *acall,
6518                           afs_uint32 *Seconds,
6519                           afs_uint32 *USeconds)
6520 {
6521     afs_int32 code;
6522     struct rx_connection *tcon;
6523     struct timeval tpl;
6524 #if FS_STATS_DETAILED
6525     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6526     struct timeval opStartTime,
6527                    opStopTime;              /* Start/stop times for RPC op*/
6528     struct timeval elapsedTime;             /* Transfer time */
6529
6530     /*
6531      * Set our stats pointer, remember when the RPC operation started, and
6532      * tally the operation.
6533      */
6534     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
6535     FS_LOCK
6536     (opP->numOps)++;
6537     FS_UNLOCK
6538     TM_GetTimeOfDay(&opStartTime, 0);
6539 #endif /* FS_STATS_DETAILED */
6540
6541     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
6542         goto Bad_GetTime;
6543
6544     FS_LOCK
6545     AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
6546     FS_UNLOCK
6547
6548     TM_GetTimeOfDay(&tpl, 0);
6549     *Seconds = tpl.tv_sec;
6550     *USeconds = tpl.tv_usec;
6551
6552     ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
6553     
6554 Bad_GetTime:
6555     CallPostamble(tcon);
6556
6557 #if FS_STATS_DETAILED
6558     TM_GetTimeOfDay(&opStopTime, 0);
6559     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6560     if (code == 0) {
6561       FS_LOCK
6562       (opP->numSuccesses)++;
6563       fs_stats_AddTo((opP->sumTime), elapsedTime);
6564       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6565       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6566         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6567       }
6568       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6569         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6570       }
6571       FS_UNLOCK
6572     }
6573
6574 #endif /* FS_STATS_DETAILED */
6575
6576     return code;
6577
6578 } /*SRXAFS_GetTime*/
6579
6580
6581 /*
6582  * FetchData_RXStyle
6583  *
6584  * Purpose:
6585  *      Implement a client's data fetch using Rx.
6586  *
6587  * Arguments:
6588  *      volptr          : Ptr to the given volume's info.
6589  *      targetptr       : Pointer to the vnode involved.
6590  *      Call            : Ptr to the Rx call involved.
6591  *      Pos             : Offset within the file.
6592  *      Len             : Length in bytes to read; this value is bogus!
6593  * if FS_STATS_DETAILED
6594  *      a_bytesToFetchP : Set to the number of bytes to be fetched from
6595  *                        the File Server.
6596  *      a_bytesFetchedP : Set to the actual number of bytes fetched from
6597  *                        the File Server.
6598  * endif
6599  */
6600
6601 afs_int32
6602 FetchData_RXStyle(Volume *volptr, 
6603                   Vnode *targetptr, 
6604                   register struct rx_call *Call,
6605                   afs_size_t Pos,
6606                   afs_size_t Len,
6607                   afs_int32 Int64Mode,
6608 #if FS_STATS_DETAILED
6609                   afs_size_t *a_bytesToFetchP,
6610                   afs_size_t *a_bytesFetchedP
6611 #endif /* FS_STATS_DETAILED */
6612                   )
6613 {
6614     struct timeval StartTime, StopTime; /* used to calculate file  transfer rates */
6615     int errorCode = 0;                  /* Returned error code to caller */
6616     int code;
6617     IHandle_t *ihP;
6618     FdHandle_t *fdP;
6619 #ifdef AFS_NT40_ENV
6620     register char *tbuffer;
6621 #else /* AFS_NT40_ENV */
6622     struct iovec tiov[RX_MAXIOVECS];
6623     int tnio;
6624 #endif /* AFS_NT40_ENV */
6625     afs_size_t tlen;
6626     afs_int32 optSize;
6627     struct stat tstat;
6628 #ifdef  AFS_AIX_ENV
6629     struct statfs tstatfs;
6630 #endif
6631
6632 #if FS_STATS_DETAILED
6633     /*
6634      * Initialize the byte count arguments.
6635      */
6636     (*a_bytesToFetchP) = 0;
6637     (*a_bytesFetchedP) = 0;
6638 #endif /* FS_STATS_DETAILED */
6639
6640 #ifdef AFS_LARGEFILE_ENV
6641     ViceLog(25, ("FetchData_RXStyle: Pos (0X%x,0X%x), Len (0X%x,0X%x)\n",
6642                  (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6643                  (unsigned) (Len >> 32), (unsigned) (Len & 0xffffffff)));
6644 #else /* !AFS_LARGEFILE_ENV */
6645     ViceLog(25, ("FetchData_RXStyle: Pos 0X%x, Len 0X%x\n",
6646                  (unsigned) Pos,
6647                  (unsigned) Len));
6648 #endif /* !AFS_LARGEFILE_ENV */
6649
6650     if (!VN_GET_INO(targetptr)) {
6651         afs_int32       zero = htonl(0);
6652         /*
6653          * This is used for newly created files; we simply send 0 bytes
6654          * back to make the cache manager happy...
6655          */
6656         if (Int64Mode)
6657             rx_Write(Call, (char *)&zero, sizeof(afs_int32));   /* send 0-length  */
6658         rx_Write(Call, (char *)&zero, sizeof(afs_int32));       /* send 0-length  */
6659         return (0);
6660     }
6661     TM_GetTimeOfDay(&StartTime, 0);
6662     ihP = targetptr->handle;
6663     fdP = IH_OPEN(ihP);
6664     if (fdP == NULL) return EIO;
6665     optSize = sendBufSize;
6666     tlen = FDH_SIZE(fdP);
6667 #ifdef AFS_LARGEFILE_ENV
6668     ViceLog( 25, ("FetchData_RXStyle: file size (0X%x,0X%x)\n",
6669              (unsigned) (tlen >> 32), (unsigned) (tlen & 0xffffffff)));
6670 #else /* !AFS_LARGEFILE_ENV */
6671     ViceLog( 25, ("FetchData_RXStyle: file size 0X%x\n",
6672                   (unsigned) tlen));
6673 #endif /* !AFS_LARGEFILE_ENV */
6674     if (tlen < 0) {
6675         FDH_CLOSE(fdP);
6676         return EIO;
6677     }
6678
6679     if (Pos + Len > tlen) Len = tlen - Pos;     /* get length we should send */
6680     FDH_SEEK(fdP, Pos, 0);
6681     {
6682         afs_int32       high, low;
6683         SplitOffsetOrSize(Len, high, low);
6684         assert(Int64Mode || high==0);
6685         if (Int64Mode) {
6686             high = htonl(high);
6687             rx_Write(Call, (char *)&high, sizeof(afs_int32)); /* High order bits */
6688         }
6689         low = htonl(low);
6690         rx_Write(Call, (char *)&low, sizeof(afs_int32));        /* send length on fetch */
6691     }
6692 #if FS_STATS_DETAILED
6693     (*a_bytesToFetchP) = Len;
6694 #endif /* FS_STATS_DETAILED */
6695 #ifdef AFS_NT40_ENV
6696     tbuffer = AllocSendBuffer();
6697 #endif /* AFS_NT40_ENV */
6698     while (Len > 0) {
6699         if (Len > optSize) tlen = optSize;
6700         else tlen = Len;
6701 #ifdef AFS_NT40_ENV
6702         errorCode = FDH_READ(fdP, tbuffer, tlen);
6703         if (errorCode != tlen) {
6704             FDH_CLOSE(fdP);
6705             FreeSendBuffer((struct afs_buffer *) tbuffer);
6706             return EIO;
6707         }
6708         errorCode = rx_Write(Call, tbuffer, tlen);
6709 #else /* AFS_NT40_ENV */
6710         errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6711         if (errorCode <= 0) {
6712             FDH_CLOSE(fdP);
6713             return EIO;
6714         }
6715         tlen = errorCode;
6716         errorCode = FDH_READV(fdP, tiov, tnio);
6717         if (errorCode != tlen) {
6718             FDH_CLOSE(fdP);
6719             return EIO;
6720         }
6721         errorCode = rx_Writev(Call, tiov, tnio, tlen);
6722 #endif /* AFS_NT40_ENV */
6723 #if FS_STATS_DETAILED
6724         /*
6725           * Bump the number of bytes actually sent by the number from this
6726           * latest iteration
6727           */
6728         (*a_bytesFetchedP) += errorCode;
6729 #endif /* FS_STATS_DETAILED */
6730         if (errorCode != tlen) {
6731             FDH_CLOSE(fdP);
6732 #ifdef AFS_NT40_ENV
6733             FreeSendBuffer((struct afs_buffer *) tbuffer);
6734 #endif /* AFS_NT40_ENV */
6735             return -31;
6736         }
6737         Len -= tlen;
6738     }
6739 #ifdef AFS_NT40_ENV
6740     FreeSendBuffer((struct afs_buffer *) tbuffer);
6741 #endif /* AFS_NT40_ENV */
6742     FDH_CLOSE(fdP);
6743     TM_GetTimeOfDay(&StopTime, 0);
6744
6745     /* Adjust all Fetch Data related stats */
6746     FS_LOCK
6747     if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
6748         AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
6749     AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
6750       ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
6751     {
6752         afs_size_t      targLen;
6753         VN_GET_LEN(targLen, targetptr);
6754         AFSCallStats.TotalFetchedBytes += targLen;
6755         AFSCallStats.FetchSize1++;
6756         if (targLen < SIZE2)
6757             AFSCallStats.FetchSize2++;  
6758         else if (targLen < SIZE3)
6759             AFSCallStats.FetchSize3++;
6760         else if (targLen < SIZE4)
6761             AFSCallStats.FetchSize4++;  
6762         else
6763             AFSCallStats.FetchSize5++;
6764     }
6765     FS_UNLOCK
6766     return (0);
6767
6768 } /*FetchData_RXStyle*/
6769
6770 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, afs_size_t *size)
6771 {
6772 #ifdef AFS_NAMEI_ENV
6773     FdHandle_t *lhp;
6774     lhp = IH_OPEN(V_linkHandle(vp));
6775     if (!lhp)
6776         return EIO;
6777 #ifdef AFS_NT40_ENV
6778     *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6779 #else
6780     *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6781 #endif
6782     FDH_CLOSE(lhp);
6783     if (*lc < 0 )
6784         return -1;
6785     *size = OS_SIZE(fdP->fd_fd);
6786     return (*size == -1) ? -1 : 0;
6787 #else
6788     struct stat status;
6789
6790     if (fstat(fdP->fd_fd, &status)<0) {
6791         return -1;
6792     }
6793
6794     *lc = GetLinkCount(vp, &status);
6795     *size = status.st_size;
6796     return 0;
6797 #endif   
6798 }
6799
6800 /*
6801  * StoreData_RXStyle
6802  *
6803  * Purpose:
6804  *      Implement a client's data store using Rx.
6805  *
6806  * Arguments:
6807  *      volptr          : Ptr to the given volume's info.
6808  *      targetptr       : Pointer to the vnode involved.
6809  *      Call            : Ptr to the Rx call involved.
6810  *      Pos             : Offset within the file.
6811  *      Len             : Length in bytes to store; this value is bogus!
6812  * if FS_STATS_DETAILED
6813  *      a_bytesToStoreP : Set to the number of bytes to be stored to
6814  *                        the File Server.
6815  *      a_bytesStoredP  : Set to the actual number of bytes stored to
6816  *                        the File Server.
6817  * endif
6818  */
6819 afs_int32
6820 StoreData_RXStyle(Volume *volptr,
6821                   Vnode *targetptr,
6822                   struct AFSFid *Fid,
6823                   struct client *client,
6824                   register struct rx_call *Call,
6825                   afs_offs_t Pos,
6826                   afs_offs_t Length,
6827                   afs_offs_t FileLength,
6828                   int sync,
6829 #if FS_STATS_DETAILED
6830                   afs_size_t *a_bytesToStoreP,
6831                   afs_size_t *a_bytesStoredP
6832 #endif /* FS_STATS_DETAILED */
6833                   )
6834 {
6835     afs_size_t bytesTransfered;         /* number of bytes actually transfered */
6836     struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
6837     int errorCode = 0;                  /* Returned error code to caller */
6838 #ifdef AFS_NT40_ENV
6839     register char *tbuffer;             /* data copying buffer */
6840 #else /* AFS_NT40_ENV */
6841     struct iovec tiov[RX_MAXIOVECS];    /* no data copying with iovec */
6842     int tnio;                           /* temp for iovec size */
6843 #endif /* AFS_NT40_ENV */
6844     afs_size_t  tlen;                   /* temp for xfr length */
6845     Inode tinode;                       /* inode for I/O */
6846     afs_size_t optSize;                 /* optimal transfer size */
6847     afs_size_t DataLength;              /* size of inode */
6848     afs_size_t TruncatedLength;         /* size after ftruncate */
6849     afs_offs_t NewLength;               /* size after this store completes */
6850     afs_size_t adjustSize;              /* bytes to call VAdjust... with */
6851     int linkCount;                      /* link count on inode */
6852     int code;
6853     FdHandle_t *fdP;
6854     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
6855
6856 #if FS_STATS_DETAILED
6857     /*
6858      * Initialize the byte count arguments.
6859      */
6860     (*a_bytesToStoreP) = 0;
6861     (*a_bytesStoredP)  = 0;
6862 #endif /* FS_STATS_DETAILED */
6863
6864     /*
6865      * We break the callbacks here so that the following signal will not
6866      * leave a window.
6867      */
6868     BreakCallBack(client->host, Fid, 0);
6869
6870     if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
6871         /* the inode should have been created in Alloc_NewVnode */
6872         logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
6873         ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
6874                 Fid->Volume, Fid->Vnode, Fid->Unique, 
6875                 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
6876         return ENOENT;  /* is this proper error code? */
6877     }
6878     else {
6879         /*
6880          * See if the file has several links (from other volumes).  If it
6881          * does, then we have to make a copy before changing it to avoid
6882          *changing read-only clones of this dude
6883          */
6884         ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
6885                      PrintInode(NULL, VN_GET_INO(targetptr))));
6886         fdP = IH_OPEN(targetptr->handle);
6887         if (fdP == NULL) 
6888             return ENOENT;
6889         if (GetLinkCountAndSize(volptr, fdP, &linkCount,
6890                                 &DataLength)<0) {
6891             FDH_CLOSE(fdP);
6892             return EIO;
6893         }
6894         
6895         if (linkCount != 1) {
6896             afs_size_t size;
6897             ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
6898                          PrintInode(NULL, VN_GET_INO(targetptr))));
6899             /* other volumes share this data, better copy it first */
6900
6901             /* Adjust the disk block count by the creation of the new inode.
6902              * We call the special VDiskUsage so we don't adjust the volume's
6903              * quota since we don't want to penalyze the user for afs's internal
6904              * mechanisms (i.e. copy on write overhead.) Also the right size
6905              * of the disk will be recorded...
6906              */
6907             FDH_CLOSE(fdP);
6908             VN_GET_LEN(size, targetptr);
6909             volptr->partition->flags &= ~PART_DONTUPDATE;
6910             VSetPartitionDiskUsage(volptr->partition);
6911             volptr->partition->flags |= PART_DONTUPDATE;
6912             if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
6913                 volptr->partition->flags &= ~PART_DONTUPDATE;
6914                 return(errorCode);
6915             }
6916
6917             ViceLog(25, ("StoreData : calling CopyOnWrite on  target dir\n"));
6918             if ((errorCode = CopyOnWrite(targetptr, volptr)))
6919             {
6920                 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6921                 volptr->partition->flags &= ~PART_DONTUPDATE;
6922                 return (errorCode);
6923             }
6924             volptr->partition->flags &= ~PART_DONTUPDATE;
6925             VSetPartitionDiskUsage(volptr->partition);
6926             fdP = IH_OPEN(targetptr->handle);
6927             if (fdP == NULL)  {
6928                 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
6929                 return ENOENT;
6930             }
6931         }
6932         tinode = VN_GET_INO(targetptr);
6933     }
6934     assert(VALID_INO(tinode));
6935
6936     /* compute new file length */
6937     NewLength = DataLength;
6938     if (FileLength < NewLength)
6939         /* simulate truncate */
6940         NewLength = FileLength; 
6941     TruncatedLength = NewLength; /* remember length after possible ftruncate */
6942     if (Pos + Length > NewLength)
6943         NewLength = Pos+Length;   /* and write */
6944
6945     /* adjust the disk block count by the difference in the files */
6946     {
6947         afs_size_t      targSize;
6948         VN_GET_LEN(targSize, targetptr);
6949         adjustSize = nBlocks(NewLength) - nBlocks(targSize);
6950     }
6951     if((errorCode = AdjustDiskUsage(volptr, adjustSize,
6952                                    adjustSize - SpareComp(volptr)))) {
6953         FDH_CLOSE(fdP);
6954         return(errorCode);
6955     }
6956
6957     /* can signal cache manager to proceed from close now */
6958     /* this bit means that the locks are set and protections are OK */
6959     rx_SetLocalStatus(Call, 1);
6960
6961     TM_GetTimeOfDay(&StartTime, 0);
6962
6963     optSize = sendBufSize;
6964
6965 #ifdef AFS_LARGEFILE_ENV
6966     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",
6967                  (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6968                  (unsigned) (DataLength >> 32), (unsigned) (DataLength & 0xffffffff),
6969                  (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff),
6970                  (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff)));
6971 #else /* !AFS_LARGEFILE_ENV */
6972     ViceLog(25, ("StoreData_RXStyle: Pos 0X%x, DataLength 0X%x, FileLength 0X%x, Length 0X%x\n",
6973                  (unsigned) Pos,
6974                  (unsigned) DataLength,
6975                  (unsigned) FileLength,
6976                  (unsigned) Length));
6977 #endif /* !AFS_LARGEFILE_ENV */
6978
6979     /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
6980     if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
6981     if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
6982     bytesTransfered = 0;
6983 #ifdef AFS_NT40_ENV
6984     tbuffer = AllocSendBuffer();
6985 #endif /* AFS_NT40_ENV */
6986     /* if length == 0, the loop below isn't going to do anything, including
6987      * extend the length of the inode, which it must do, since the file system
6988      * assumes that the inode length == vnode's file length.  So, we extend
6989      * the file length manually if need be.  Note that if file is bigger than
6990      * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
6991      * do what we're going to do below.
6992      */
6993     if (Length == 0 && Pos > TruncatedLength) {
6994         /* Set the file's length; we've already done an lseek to the right
6995          * spot above.
6996          */
6997         errorCode = FDH_WRITE(fdP, &tlen, 1);
6998         if (errorCode != 1) goto done;
6999         errorCode = FDH_TRUNC(fdP, Pos);
7000     }
7001     else {
7002         /* have some data to copy */
7003 #if FS_STATS_DETAILED
7004         (*a_bytesToStoreP) = Length;
7005 #endif /* FS_STATS_DETAILED */
7006         while (1) {
7007             if (bytesTransfered >= Length) {
7008                 errorCode = 0;
7009                 break;
7010             }
7011             tlen = Length -     bytesTransfered;    /* how much more to do */
7012             if (tlen > optSize) tlen = optSize; /* bound by buffer size */
7013 #ifdef AFS_NT40_ENV
7014             errorCode = rx_Read(Call, tbuffer, tlen);
7015 #else /* AFS_NT40_ENV */
7016             errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
7017 #endif /* AFS_NT40_ENV */
7018 #if FS_STATS_DETAILED
7019             (*a_bytesStoredP) += errorCode;
7020 #endif /* FS_STATS_DETAILED */
7021             if (errorCode <= 0) {
7022                 errorCode = -32;
7023                 break;
7024             }
7025             tlen = errorCode;
7026 #ifdef AFS_NT40_ENV
7027             errorCode = FDH_WRITE(fdP, tbuffer, tlen);
7028 #else /* AFS_NT40_ENV */
7029             errorCode = FDH_WRITEV(fdP, tiov, tnio);
7030 #endif /* AFS_NT40_ENV */
7031             if (errorCode != tlen) {
7032                 errorCode = VDISKFULL;
7033                 break;
7034             }
7035             bytesTransfered += tlen;
7036         }
7037     }
7038   done:
7039 #ifdef AFS_NT40_ENV
7040     FreeSendBuffer((struct afs_buffer *) tbuffer);
7041 #endif /* AFS_NT40_ENV */
7042     if (sync) {
7043       FDH_SYNC(fdP);
7044     }
7045     if (errorCode) {
7046         afs_size_t      nfSize = FDH_SIZE(fdP);
7047         /* something went wrong: adjust size and return */
7048         VN_SET_LEN(targetptr, nfSize); /* set new file size. */
7049         /* changed_newTime is tested in StoreData to detemine if we
7050          * need to update the target vnode.
7051          */
7052         targetptr->changed_newTime = 1;
7053         FDH_CLOSE(fdP);
7054         /* set disk usage to be correct */
7055         VAdjustDiskUsage(&errorCode, volptr,
7056                          (afs_size_t)(nBlocks(nfSize) - nBlocks(NewLength)), 
7057                          (afs_size_t) 0);
7058         return errorCode;
7059     }
7060     FDH_CLOSE(fdP);
7061
7062     TM_GetTimeOfDay(&StopTime, 0);
7063
7064     VN_SET_LEN(targetptr, NewLength);
7065
7066     /* Update all StoreData related stats */
7067     FS_LOCK
7068     if (AFSCallStats.TotalStoredBytes > 2000000000)     /* reset if over 2 billion */
7069         AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
7070     AFSCallStats.StoreSize1++;                  /* Piggybacked data */
7071     {
7072         afs_size_t      targLen;
7073         VN_GET_LEN(targLen, targetptr);
7074         if (targLen < SIZE2)
7075             AFSCallStats.StoreSize2++;
7076         else if (targLen < SIZE3)
7077             AFSCallStats.StoreSize3++;
7078         else if (targLen < SIZE4)
7079             AFSCallStats.StoreSize4++;
7080         else
7081             AFSCallStats.StoreSize5++;
7082     }
7083     FS_UNLOCK
7084     return(errorCode);
7085
7086 } /*StoreData_RXStyle*/
7087
7088