2aa0e35d5a228b4fca8ed59f56b12c2f6c10c29d
[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), 
353                         ntohs(thost->port)));
354             code = -1;
355         } else {
356             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
357                         afs_inet_ntoa_r(thost->host, hoststr), 
358                         ntohs(thost->port)));
359             if (BreakDelayedCallBacks_r(thost)) {
360                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
361                         afs_inet_ntoa_r(thost->host, hoststr)));
362                 code = -1;
363             }
364         }
365       }
366     } else {
367        code =  0;
368     }
369
370     h_ReleaseClient_r(tclient);
371     h_Unlock_r(thost);
372     H_UNLOCK
373     return code;      
374
375 } /*CallPreamble*/
376
377
378 static void CallPostamble(register struct rx_connection *aconn)
379 {
380     struct host *thost;
381     struct client *tclient;
382
383     H_LOCK
384     tclient = h_FindClient_r(aconn);
385     thost = tclient->host;
386     h_ReleaseClient_r(tclient);
387     h_Release_r(thost);
388     H_UNLOCK
389
390 } /*CallPostamble*/
391
392 /*
393  * Returns the volume and vnode pointers associated with file Fid; the lock
394  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
395  * are incremented and they must be eventualy released.
396  */
397 static afs_int32
398 CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock)
399 {
400     int fileCode = 0;
401     int errorCode = -1;
402     static struct timeval restartedat = {0,0};
403
404     if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
405         return(EINVAL);
406     if ((*volptr) == 0) {
407       extern int VInit;
408
409       while(1) {
410         errorCode = 0;
411         *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
412         if (!errorCode) {
413           assert (*volptr);
414           break;
415         }
416         if ((errorCode == VOFFLINE) && (VInit < 2)) {
417             /* The volume we want may not be attached yet because
418              * the volume initialization is not yet complete.
419              * We can do several things: 
420              *     1.  return -1, which will cause users to see
421              *         "connection timed out".  This is more or
422              *         less the same as always, except that the servers
423              *         may appear to bounce up and down while they
424              *         are actually restarting.
425              *     2.  return VBUSY which will cause clients to 
426              *         sleep and retry for 6.5 - 15 minutes, depending
427              *         on what version of the CM they are running.  If
428              *         the file server takes longer than that interval 
429              *         to attach the desired volume, then the application
430              *         will see an ENODEV or EIO.  This approach has 
431              *         the advantage that volumes which have been attached
432              *         are immediately available, it keeps the server's
433              *         immediate backlog low, and the call is interruptible
434              *         by the user.  Users see "waiting for busy volume."
435              *     3.  sleep here and retry.  Some people like this approach
436              *         because there is no danger of seeing errors.  However, 
437              *         this approach only works with a bounded number of 
438              *         clients, since the pending queues will grow without
439              *         stopping.  It might be better to find a way to take
440              *         this call and stick it back on a queue in order to
441              *         recycle this thread for a different request.    
442              *     4.  Return a new error code, which new cache managers will
443              *         know enough to interpret as "sleep and retry", without
444              *         the upper bound of 6-15 minutes that is imposed by the
445              *         VBUSY handling.  Users will see "waiting for
446              *         busy volume," so they know that something is
447              *         happening.  Old cache managers must be able to do  
448              *         something reasonable with this, for instance, mark the
449              *         server down.  Fortunately, any error code < 0
450              *         will elicit that behavior. See #1.
451              *     5.  Some combination of the above.  I like doing #2 for 10
452              *         minutes, followed by #4.  3.1b and 3.2 cache managers
453              *         will be fine as long as the restart period is
454              *         not longer than 6.5 minutes, otherwise they may
455              *         return ENODEV to users.  3.3 cache managers will be
456              *         fine for 10 minutes, then will return
457              *         ETIMEDOUT.  3.4 cache managers will just wait
458              *         until the call works or fails definitively.
459              *  NB. The problem with 2,3,4,5 is that old clients won't
460              *  fail over to an alternate read-only replica while this
461              *  server is restarting.  3.4 clients will fail over right away.
462              */
463           if (restartedat.tv_sec == 0) {
464             /* I'm not really worried about when we restarted, I'm   */
465             /* just worried about when the first VBUSY was returned. */
466             TM_GetTimeOfDay(&restartedat, 0);
467             return(busyonrst?VBUSY:VRESTARTING);
468           }
469           else {
470             struct timeval now;
471             TM_GetTimeOfDay(&now, 0);
472             if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
473               return(busyonrst?VBUSY:VRESTARTING);
474             }
475             else {
476               return (VRESTARTING);
477             }
478           }
479         }
480           /* allow read operations on busy volume */
481         else if(errorCode==VBUSY && lock==READ_LOCK) {
482           errorCode=0;
483           break;
484         }
485         else if (errorCode)
486           return(errorCode);
487       }
488     }
489     assert (*volptr);
490
491     /* get the vnode  */
492     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
493     if (errorCode)
494         return(errorCode);
495     if ((*vptr)->disk.uniquifier != fid->Unique) {
496         VPutVnode(&fileCode, *vptr);
497         assert(fileCode == 0);
498         *vptr = 0;
499         return(VNOVNODE);   /* return the right error code, at least */
500     }
501     return(0);
502 } /*CheckVnode*/
503
504 /*
505  * This routine returns the ACL associated with the targetptr. If the
506  * targetptr isn't a directory, we access its parent dir and get the ACL
507  * thru the parent; in such case the parent's vnode is returned in
508  * READ_LOCK mode.
509  */
510 static afs_int32
511 SetAccessList(Vnode **targetptr,
512               Volume **volume,
513               struct acl_accessList **ACL,
514               int * ACLSize,
515               Vnode **parent,
516               AFSFid *Fid,
517               int Lock)
518 {
519     if ((*targetptr)->disk.type == vDirectory) {
520         *parent = 0;
521         *ACL = VVnodeACL(*targetptr);
522         *ACLSize = VAclSize(*targetptr);
523         return(0);
524     }
525     else {
526         assert(Fid != 0);
527         while(1) {
528             VnodeId parentvnode;
529             int errorCode = 0;
530             
531             parentvnode = (*targetptr)->disk.parent;
532             VPutVnode(&errorCode,*targetptr);
533             *targetptr = 0;
534             if (errorCode) return(errorCode);
535             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
536             if (errorCode) return(errorCode);
537             *ACL = VVnodeACL(*parent);
538             *ACLSize = VAclSize(*parent);
539             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
540                 return(errorCode);
541             if ((*targetptr)->disk.parent != parentvnode) {
542                 VPutVnode(&errorCode, *parent);
543                 *parent = 0;
544                 if (errorCode) return(errorCode);
545             } else
546                 return(0);
547         }
548     }
549
550 } /*SetAccessList*/
551
552 /*
553  * Compare the directory's ACL with the user's access rights in the client
554  * connection and return the user's and everybody else's access permissions
555  * in rights and anyrights, respectively
556  */
557 static afs_int32
558 GetRights (struct client *client,
559            struct acl_accessList *ACL,
560            afs_int32 *rights,
561            afs_int32 *anyrights)
562 {
563     extern prlist SystemAnyUserCPS;
564     afs_int32 hrights = 0;
565     int code;
566
567     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
568
569         ViceLog(0,("CheckRights failed\n"));
570         *anyrights = 0;
571     }
572     *rights = 0;
573     acl_CheckRights(ACL, &client->CPS, rights);
574
575         /* wait if somebody else is already doing the getCPS call */
576     H_LOCK
577     while ( client->host->hostFlags & HCPS_INPROGRESS )
578     {
579         client->host->hostFlags |= HCPS_WAITING;  /* I am waiting */
580 #ifdef AFS_PTHREAD_ENV
581         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
582 #else /* AFS_PTHREAD_ENV */
583         if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
584                 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
585 #endif /* AFS_PTHREAD_ENV */
586     }
587
588     if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
589         ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
590     } else
591         acl_CheckRights(ACL, &client->host->hcps, &hrights);
592     H_UNLOCK
593     /* Allow system:admin the rights given with the -implicit option */
594     if (acl_IsAMember(SystemId, &client->CPS))
595         *rights |= implicitAdminRights;
596     *rights |= hrights;
597     *anyrights |= hrights;
598
599     return(0);
600
601 } /*GetRights*/
602
603 /*
604  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
605  * a System:Administrator)
606  */
607 static afs_int32
608 VanillaUser(struct client *client)
609 {
610     if (acl_IsAMember(SystemId, &client->CPS))
611         return(0);  /* not a system administrator, then you're "vanilla" */
612     return(1);
613
614 } /*VanillaUser*/
615
616
617 /*
618  * This unusual afs_int32-parameter routine encapsulates all volume package related
619  * operations together in a single function; it's called by almost all AFS
620  * interface calls.
621  */
622 static afs_int32
623 GetVolumePackage(struct rx_connection *tcon,
624                  AFSFid *Fid,
625                  Volume **volptr,
626                  Vnode **targetptr,
627                  int chkforDir,
628                  Vnode **parent,
629                  struct client **client,
630                  int locktype,
631                  afs_int32 *rights, 
632                  afs_int32 *anyrights)
633 {
634     struct acl_accessList * aCL;    /* Internal access List */
635     int aCLSize;            /* size of the access list */
636     int errorCode = 0;      /* return code to caller */
637
638     if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
639         return(errorCode);
640     if (chkforDir) {
641         if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
642             return(EISDIR);
643         else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
644             return(ENOTDIR);
645     }
646     if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
647         return(errorCode);
648     if (chkforDir == MustBeDIR) assert((*parent) == 0);
649     if ((errorCode = GetClient(tcon, client)) != 0)
650         return(errorCode);
651     if (!(*client))
652         return(EINVAL);
653     assert(GetRights(*client, aCL, rights, anyrights) == 0);
654     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
655     if ((*targetptr)->disk.type != vDirectory) {
656         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
657         if ((*targetptr)->disk.owner == (*client)->ViceId)
658             (*rights) |= PRSFS_ADMINISTER;
659         else
660             (*rights) &= ~PRSFS_ADMINISTER;
661     }
662 #ifdef ADMIN_IMPLICIT_LOOKUP
663     /* admins get automatic lookup on everything */
664     if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
665 #endif /* ADMIN_IMPLICIT_LOOKUP */
666     return errorCode;
667
668 } /*GetVolumePackage*/
669
670
671 /*
672  * This is the opposite of GetVolumePackage(), and is always used at the end of
673  * AFS calls to put back all used vnodes and the volume in the proper order!
674  */
675 static afs_int32
676 PutVolumePackage(Vnode *parentwhentargetnotdir, 
677                  Vnode *targetptr,
678                  Vnode *parentptr,
679                  Volume *volptr)
680 {
681     int fileCode = 0;   /* Error code returned by the volume package */
682
683     if (parentwhentargetnotdir) {
684         VPutVnode(&fileCode, parentwhentargetnotdir);
685         assert(!fileCode || (fileCode == VSALVAGE));
686     }
687     if (targetptr) {
688         VPutVnode(&fileCode, targetptr);
689         assert(!fileCode || (fileCode == VSALVAGE));
690     }
691     if (parentptr) {
692         VPutVnode(&fileCode, parentptr);
693         assert(!fileCode || (fileCode == VSALVAGE));
694     }
695     if (volptr) {
696         VPutVolume(volptr);
697     }
698 } /*PutVolumePackage*/
699
700 static int VolumeOwner (register struct client *client, 
701                         register Vnode *targetptr)
702 {
703     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
704
705     if (owner >= 0)
706         return (client->ViceId == owner);
707     else {
708         /* 
709          * We don't have to check for host's cps since only regular
710          * viceid are volume owners.
711          */
712         return (acl_IsAMember(owner, &client->CPS));
713     }
714
715 } /*VolumeOwner*/
716
717 static int VolumeRootVnode (Vnode *targetptr)
718 {
719     return ((targetptr->vnodeNumber == ROOTVNODE) &&
720             (targetptr->disk.uniquifier == 1));
721
722 } /*VolumeRootVnode*/
723
724 /*
725  * Check if target file has the proper access permissions for the Fetch
726  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
727  * StoreStatus) related calls
728  */
729 /* this code should probably just set a "priv" flag where all the audit events
730  * are now, and only generate the audit event once at the end of the routine, 
731  * thus only generating the event if all the checks succeed, but only because
732  * of the privilege       XXX
733  */
734 static afs_int32
735 Check_PermissionRights(Vnode *targetptr,
736                        struct client *client,
737                        afs_int32 rights,
738                        int CallingRoutine,
739                        AFSStoreStatus *InStatus)
740 {
741     int errorCode = 0;
742 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
743 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
744 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
745
746     if (CallingRoutine & CHK_FETCH) {
747 #ifdef  CMUCS
748         if (VanillaUser(client)) 
749 #else
750         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) 
751 #endif
752           {
753             if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
754                 if (   !(rights & PRSFS_LOOKUP)
755 #ifdef ADMIN_IMPLICIT_LOOKUP  
756                     /* grant admins fetch on all directories */
757                     && VanillaUser(client)
758 #endif /* ADMIN_IMPLICIT_LOOKUP */
759                     && !VolumeOwner(client, targetptr))
760                     return(EACCES);
761             } else {    /* file */
762                 /* must have read access, or be owner and have insert access */
763                 if (!(rights & PRSFS_READ) &&
764                     !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
765                     return(EACCES);
766             }
767             if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
768 #ifdef USE_GROUP_PERMS
769                 if (!OWNSp(client, targetptr) &&
770                     !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
771                     errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
772                                  ? 0: EACCES);
773                 } else {
774                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
775                                 ? 0: EACCES);
776                 }
777 #else
778                 /*
779                  * The check with the ownership below is a kludge to allow
780                  * reading of files created with no read permission. The owner
781                  * of the file is always allowed to read it.
782                  */
783                 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
784                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
785 #endif
786         }
787         else /*  !VanillaUser(client) && !FetchData */ {
788           osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
789                                         AUD_INT, CallingRoutine, AUD_END);
790         }
791     }
792     else { /* a store operation */
793       if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
794           && (CallingRoutine != CHK_STOREACL)
795           && (targetptr->disk.type == vFile))
796         {
797           /* bypass protection checks on first store after a create
798            * for the creator; also prevent chowns during this time
799            * unless you are a system administrator */
800           /******  InStatus->Owner && UnixModeBits better be SET!! */
801           if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
802             if (readonlyServer) 
803               return(VREADONLY);
804             else if (VanillaUser (client)) 
805               return(EPERM);      /* Was EACCES */
806             else
807               osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
808                                             AUD_INT, CallingRoutine, AUD_END);
809           }
810         } else {
811           if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
812             osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
813                                           AUD_INT, CallingRoutine, AUD_END);
814           }
815           else {
816             if (readonlyServer) {
817                 return(VREADONLY);
818             }
819             if (CallingRoutine == CHK_STOREACL) {
820               if (!(rights & PRSFS_ADMINISTER) &&
821                   !VolumeOwner(client, targetptr)) return(EACCES);
822             }
823             else {      /* store data or status */
824               /* watch for chowns and chgrps */
825               if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
826                 if (readonlyServer) 
827                   return(VREADONLY);
828                 else if (VanillaUser (client)) 
829                   return(EPERM);        /* Was EACCES */
830                 else
831                   osi_audit(PrivilegeEvent, 0,
832                             AUD_INT, (client ? client->ViceId : 0), 
833                             AUD_INT, CallingRoutine, AUD_END);
834               }
835               /* must be sysadmin to set suid/sgid bits */
836               if ((InStatus->Mask & AFS_SETMODE) &&
837 #ifdef AFS_NT40_ENV
838                   (InStatus->UnixModeBits & 0xc00) != 0) {
839 #else
840                   (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
841 #endif
842                 if (readonlyServer)
843                   return(VREADONLY);
844                 if (VanillaUser(client))
845                   return(EACCES);
846                 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
847                                               AUD_INT, CallingRoutine, AUD_END);
848               }
849               if (CallingRoutine == CHK_STOREDATA) {
850                 if (readonlyServer)
851                   return(VREADONLY);
852                 if (!(rights & PRSFS_WRITE))
853                   return(EACCES);
854                 /* Next thing is tricky.  We want to prevent people
855                  * from writing files sans 0200 bit, but we want
856                  * creating new files with 0444 mode to work.  We
857                  * don't check the 0200 bit in the "you are the owner"
858                  * path above, but here we check the bit.  However, if
859                  * you're a system administrator, we ignore the 0200
860                  * bit anyway, since you may have fchowned the file,
861                  * too */
862 #ifdef USE_GROUP_PERMS
863                         if ((targetptr->disk.type == vFile)
864                             && VanillaUser(client)) {
865                             if (!OWNSp(client, targetptr) &&
866                                 !acl_IsAMember(targetptr->disk.owner,
867                                                &client->CPS)) {
868                                 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
869                                              ? 0: EACCES);
870                             } else {
871                                 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
872                                              ? 0 : EACCES);
873                             }
874                         } else
875 #endif
876                 if ((targetptr->disk.type != vDirectory)
877                     && (!(targetptr->disk.modeBits & OWNERWRITE)))
878                   if (readonlyServer)
879                     return(VREADONLY);
880                   if (VanillaUser(client))
881                     return(EACCES);
882                   else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
883                                                      AUD_INT, CallingRoutine, AUD_END);
884               }
885               else {  /* a status store */
886                 if (readonlyServer)
887                   return(VREADONLY);
888                 if (targetptr->disk.type == vDirectory) {
889                   if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
890                     return(EACCES);
891                 }
892                 else {  /* a file  or symlink */
893                   if (!(rights & PRSFS_WRITE)) return(EACCES);
894                 }
895               }
896             }
897           }
898         }
899     }
900     return(errorCode);
901
902 } /*Check_PermissionRights*/
903
904
905 /*
906  * The Access List information is converted from its internal form in the
907  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
908  * external form and returned back to the caller, via the AccessList
909  * structure
910  */
911 static afs_int32
912 RXFetch_AccessList(Vnode *targetptr,
913                    Vnode *parentwhentargetnotdir,
914                    struct AFSOpaque *AccessList)
915 {
916     char * eACL;        /* External access list placeholder */
917
918     if (acl_Externalize((targetptr->disk.type == vDirectory ?
919                          VVnodeACL(targetptr) :
920                          VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
921         return EIO;
922     }
923     if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
924         acl_FreeExternalACL(&eACL);
925         return(E2BIG);
926     } else {
927         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
928         AccessList->AFSOpaque_len = strlen(eACL) +1;
929     }
930     acl_FreeExternalACL(&eACL);
931     return(0);
932
933 } /*RXFetch_AccessList*/
934
935
936 /*
937  * The Access List information is converted from its external form in the
938  * input AccessList structure to the internal representation and copied into
939  * the target dir's vnode storage.
940  */
941 static afs_int32
942 RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList)
943 {
944     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
945
946     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
947         return(EINVAL);
948     if ((newACL->size + 4) > VAclSize(targetptr))
949         return(E2BIG);
950     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
951     acl_FreeACL(&newACL);
952     return(0);
953
954 } /*RXStore_AccessList*/
955
956
957 static afs_int32
958 Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir,
959                  struct AFSAccessList *AccessList)
960 {
961     char * eACL;        /* External access list placeholder */
962
963     assert(acl_Externalize((targetptr->disk.type == vDirectory ?
964                             VVnodeACL(targetptr) :
965                             VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
966     if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
967         acl_FreeExternalACL(&eACL);
968         return(E2BIG);
969     } else {
970         strcpy((char *)(AccessList->SeqBody), (char *)eACL);
971         AccessList->SeqLen = strlen(eACL) +1;
972     }
973     acl_FreeExternalACL(&eACL);
974     return(0);
975
976 } /*Fetch_AccessList*/
977
978 /*
979  * The Access List information is converted from its external form in the
980  * input AccessList structure to the internal representation and copied into
981  * the target dir's vnode storage.
982  */
983 static afs_int32
984 Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList)
985 {
986     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
987
988     if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
989         return(EINVAL);
990     if ((newACL->size + 4) > VAclSize(targetptr))
991         return(E2BIG);
992     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
993     acl_FreeACL(&newACL);
994     return(0);
995
996 } /*Store_AccessList*/
997
998
999 /* In our current implementation, each successive data store (new file
1000  * data version) creates a new inode. This function creates the new
1001  * inode, copies the old inode's contents to the new one, remove the old
1002  * inode (i.e. decrement inode count -- if it's currently used the delete
1003  * will be delayed), and modify some fields (i.e. vnode's
1004  * disk.inodeNumber and cloned)
1005  */
1006 #define COPYBUFFSIZE    8192
1007 static int CopyOnWrite(Vnode *targetptr, Volume *volptr)
1008 {
1009     Inode       ino, nearInode;
1010     int         rdlen;
1011     int         wrlen;
1012     register afs_size_t size;
1013     register int length;
1014     int ifd, ofd;
1015     char        *buff;
1016     int         rc;             /* return code */
1017     IHandle_t   *newH;  /* Use until finished copying, then cp to vnode.*/
1018     FdHandle_t  *targFdP;  /* Source Inode file handle */
1019     FdHandle_t  *newFdP; /* Dest Inode file handle */
1020
1021     if (targetptr->disk.type == vDirectory) DFlush();   /* just in case? */
1022
1023     VN_GET_LEN(size, targetptr);
1024     buff = (char *)malloc(COPYBUFFSIZE);
1025     if (buff == NULL) {
1026         return EIO;
1027     }
1028
1029     ino = VN_GET_INO(targetptr);
1030     assert(VALID_INO(ino));
1031     targFdP = IH_OPEN(targetptr->handle);
1032     if (targFdP == NULL) {
1033         rc = errno;
1034         ViceLog(0, ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n", targetptr->vnodeNumber, V_id(volptr), rc));
1035         free(buff);
1036         VTakeOffline (volptr);
1037         return rc;
1038     }
1039
1040     nearInode = VN_GET_INO(targetptr);
1041     ino = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1042                     VPartitionPath(V_partition(volptr)),nearInode, V_id(volptr),
1043                     targetptr->vnodeNumber, targetptr->disk.uniquifier,
1044                     (int)targetptr->disk.dataVersion);
1045     if (!VALID_INO(ino))
1046     {
1047         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));
1048         FDH_CLOSE(targFdP);
1049         free(buff);
1050         return ENOSPC;
1051     }
1052     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1053     newFdP = IH_OPEN(newH);
1054     assert(newFdP != NULL);
1055
1056     while(size > 0) {
1057         if (size > COPYBUFFSIZE) { /* more than a buffer */
1058             length = COPYBUFFSIZE;
1059             size -= COPYBUFFSIZE;
1060         } else {
1061             length = size;
1062             size = 0;
1063         }
1064         rdlen = FDH_READ(targFdP, buff, length); 
1065         if (rdlen == length)
1066             wrlen = FDH_WRITE(newFdP, buff, length);
1067         else
1068             wrlen = 0;
1069         /*  Callers of this function are not prepared to recover
1070          *  from error that put the filesystem in an inconsistent
1071          *  state. Make sure that we force the volume off-line if
1072          *  we some error other than ENOSPC - 4.29.99)
1073          *
1074          *  In case we are unable to write the required bytes, and the
1075          *  error code indicates that the disk is full, we roll-back to
1076          *  the initial state.
1077          */
1078         if((rdlen != length) || (wrlen != length))
1079                 if ( (wrlen < 0) && (errno == ENOSPC) ) /* disk full */
1080                 {
1081                         ViceLog(0,("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1082                                         volptr->partition->name, V_id(volptr)));
1083                         /* remove destination inode which was partially copied till now*/
1084                         FDH_REALLYCLOSE(newFdP);
1085                         IH_RELEASE(newH);
1086                         FDH_REALLYCLOSE(targFdP);
1087                         rc = IH_DEC(V_linkHandle(volptr), ino,
1088                                   V_parentId(volptr));
1089                         if (!rc ) {
1090                             ViceLog(0,("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1091                                        rc, V_id(volptr), 
1092                                        volptr->partition->name));
1093                             VTakeOffline (volptr);
1094                         }
1095                         free(buff);
1096                         return ENOSPC;
1097                 }
1098                 else {
1099                     ViceLog(0,("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1100                                V_id(volptr), volptr->partition->name, length,
1101                                rdlen, wrlen, errno));
1102 #ifdef FAST_RESTART /* if running in no-salvage, don't core the server */
1103                     ViceLog(0,("CopyOnWrite failed: taking volume offline\n"));
1104 #else /* Avoid further corruption and try to get a core. */
1105                     assert(0); 
1106 #endif
1107                     /* Decrement this inode so salvager doesn't find it. */
1108                     FDH_REALLYCLOSE(newFdP);
1109                     IH_RELEASE(newH);
1110                     FDH_REALLYCLOSE(targFdP);
1111                     rc = IH_DEC(V_linkHandle(volptr), ino,
1112                                 V_parentId(volptr));
1113                     free(buff);
1114                     VTakeOffline (volptr);
1115                     return EIO;
1116                 }
1117 #ifndef AFS_PTHREAD_ENV
1118         IOMGR_Poll();
1119 #endif /* !AFS_PTHREAD_ENV */
1120     }
1121     FDH_REALLYCLOSE(targFdP);
1122     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1123               V_parentId(volptr)) ;
1124     assert(!rc);
1125     IH_RELEASE(targetptr->handle);
1126
1127     rc = FDH_SYNC(newFdP);
1128     assert(rc == 0);
1129     FDH_CLOSE(newFdP);
1130     targetptr->handle = newH;
1131     VN_SET_INO(targetptr, ino);
1132     targetptr->disk.cloned = 0;
1133     /* Internal change to vnode, no user level change to volume - def 5445 */
1134     targetptr->changed_oldTime = 1;
1135     free(buff);
1136     return 0;                           /* success */
1137 } /*CopyOnWrite*/
1138
1139
1140 /*
1141  * Common code to handle with removing the Name (file when it's called from
1142  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1143  * given directory, parentptr.
1144  */
1145 int DT1=0, DT0=0;
1146 static afs_int32
1147 DeleteTarget(Vnode *parentptr,
1148              Volume *volptr,
1149              Vnode **targetptr,
1150              DirHandle *dir,
1151              AFSFid *fileFid,
1152              char *Name,
1153              int ChkForDir)
1154 {
1155     DirHandle childdir;     /* Handle for dir package I/O */
1156     int errorCode = 0;
1157     int code;
1158
1159     /* watch for invalid names */
1160     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1161         return (EINVAL);
1162     if (parentptr->disk.cloned) 
1163     {
1164         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1165         if ((errorCode = CopyOnWrite(parentptr, volptr)))
1166         {
1167                 ViceLog(20, ("DeleteTarget %s: CopyOnWrite failed %d\n",Name,errorCode));
1168                 return errorCode;
1169         }
1170     }
1171
1172     /* check that the file is in the directory */
1173     SetDirHandle(dir, parentptr);
1174     if (Lookup(dir, Name, fileFid))
1175         return(ENOENT);
1176     fileFid->Volume = V_id(volptr);
1177
1178     /* just-in-case check for something causing deadlock */
1179     if (fileFid->Vnode == parentptr->vnodeNumber)
1180         return(EINVAL);
1181
1182     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1183     if (errorCode) {
1184         return (errorCode);
1185     }
1186     if (ChkForDir == MustBeDIR) {
1187         if ((*targetptr)->disk.type != vDirectory)
1188             return(ENOTDIR);
1189     } else if ((*targetptr)->disk.type == vDirectory)
1190         return(EISDIR);
1191     
1192     /*assert((*targetptr)->disk.uniquifier == fileFid->Unique);*/
1193     /**
1194       * If the uniquifiers dont match then instead of asserting
1195       * take the volume offline and return VSALVAGE
1196       */
1197     if ( (*targetptr)->disk.uniquifier != fileFid->Unique ) {
1198         VTakeOffline(volptr);
1199         errorCode = VSALVAGE;
1200         return errorCode;
1201     }
1202         
1203     if (ChkForDir == MustBeDIR) {
1204         SetDirHandle(&childdir, *targetptr);
1205         if (IsEmpty(&childdir) != 0)
1206             return(EEXIST);
1207         DZap(&childdir);
1208         (*targetptr)->delete = 1;
1209     } else if ((--(*targetptr)->disk.linkCount) == 0) 
1210         (*targetptr)->delete = 1;
1211     if ((*targetptr)->delete) {
1212         if (VN_GET_INO(*targetptr)) {
1213             DT0++;
1214             IH_REALLYCLOSE((*targetptr)->handle);
1215             errorCode = IH_DEC(V_linkHandle(volptr),
1216                              VN_GET_INO(*targetptr),
1217                              V_parentId(volptr));
1218             IH_RELEASE((*targetptr)->handle);
1219             if (errorCode == -1) {
1220                 ViceLog(0, ("DT: inode=%s, name=%s, errno=%d\n",
1221                             PrintInode(NULL, VN_GET_INO(*targetptr)),
1222                             Name, errno));
1223 #ifdef  AFS_DEC_ENV
1224                 if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
1225 #else
1226                 if (errno != ENOENT) 
1227 #endif
1228                     {
1229                     ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
1230                                 volptr->hashid));
1231                     VTakeOffline(volptr);
1232                     return (EIO);
1233                     }
1234                 DT1++;
1235                 errorCode = 0;
1236             }
1237         }
1238         VN_SET_INO(*targetptr, (Inode)0);
1239         {
1240             afs_size_t  adjLength;
1241             VN_GET_LEN(adjLength, *targetptr);
1242             VAdjustDiskUsage(&errorCode, volptr,
1243                              -nBlocks(adjLength),
1244                              (afs_size_t) 0);
1245         }
1246     }
1247     
1248     (*targetptr)->changed_newTime = 1; /* Status change of deleted file/dir */
1249
1250     code = Delete(dir,(char *) Name);
1251     if (code) {
1252        ViceLog(0, ("Error %d deleting %s\n", code,
1253                    (((*targetptr)->disk.type== Directory)?"directory":"file")));
1254        ViceLog(0, ("Volume %u now offline, must be salvaged.\n", 
1255                   volptr->hashid));
1256        VTakeOffline(volptr);
1257        if (!errorCode) errorCode = code;
1258     }
1259
1260     DFlush();
1261     return(errorCode);
1262
1263 } /*DeleteTarget*/
1264
1265
1266 /*
1267  * This routine updates the parent directory's status block after the
1268  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1269  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1270  * been performed.
1271  */
1272 static void
1273 Update_ParentVnodeStatus(Vnode *parentptr,
1274                          Volume *volptr,
1275                          DirHandle *dir,
1276                          int author,
1277                          int linkcount,
1278 #if FS_STATS_DETAILED
1279                          char a_inSameNetwork
1280 #endif /* FS_STATS_DETAILED */
1281                          )
1282 {
1283     afs_offs_t newlength;       /* Holds new directory length */
1284     afs_offs_t parentLength;
1285     int errorCode;
1286 #if FS_STATS_DETAILED
1287     Date currDate;              /*Current date*/
1288     int writeIdx;               /*Write index to bump*/
1289     int timeIdx;                /*Authorship time index to bump*/
1290 #endif /* FS_STATS_DETAILED */
1291
1292     parentptr->disk.dataVersion++;
1293     newlength = Length(dir);
1294     /* 
1295      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1296      * (create, symlink, link, makedir) so we need to check if we have enough space
1297      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1298      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1299      */
1300     VN_GET_LEN(parentLength, parentptr);
1301     if (nBlocks(newlength) != nBlocks(parentLength)) {
1302         VAdjustDiskUsage(&errorCode, volptr, 
1303                          (nBlocks(newlength) - nBlocks(parentLength)),
1304                          (nBlocks(newlength) - nBlocks(parentLength)));
1305     }
1306     VN_SET_LEN(parentptr, newlength);
1307
1308 #if FS_STATS_DETAILED
1309     /*
1310      * Update directory write stats for this volume.  Note that the auth
1311      * counter is located immediately after its associated ``distance''
1312      * counter.
1313      */
1314     if (a_inSameNetwork)
1315         writeIdx = VOL_STATS_SAME_NET;
1316     else
1317         writeIdx = VOL_STATS_DIFF_NET;
1318     V_stat_writes(volptr, writeIdx)++;
1319     if (author != AnonymousID) {
1320         V_stat_writes(volptr, writeIdx+1)++;
1321     }
1322
1323     /*
1324      * Update the volume's authorship information in response to this
1325      * directory operation.  Get the current time, decide to which time
1326      * slot this operation belongs, and bump the appropriate slot.
1327      */
1328     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1329     timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1330                currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1331                currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1332                currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1333                currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1334                VOL_STATS_TIME_IDX_5);
1335     if (parentptr->disk.author == author) {
1336         V_stat_dirSameAuthor(volptr, timeIdx)++;
1337     }
1338     else {
1339         V_stat_dirDiffAuthor(volptr, timeIdx)++;
1340     }
1341 #endif /* FS_STATS_DETAILED */
1342
1343     parentptr->disk.author = author;
1344     parentptr->disk.linkCount = linkcount;
1345     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
1346     parentptr->disk.serverModifyTime = FT_ApproxTime();
1347     parentptr->changed_newTime = 1; /* vnode changed, write it back. */
1348 }
1349
1350
1351 /*
1352  * Update the target file's (or dir's) status block after the specified
1353  * operation is complete. Note that some other fields maybe updated by
1354  * the individual module.
1355  */
1356
1357 /* XXX INCOMPLETE - More attention is needed here! */
1358 static void
1359 Update_TargetVnodeStatus(Vnode *targetptr,
1360                          afs_uint32 Caller,
1361                          struct client *client,
1362                          AFSStoreStatus *InStatus,
1363                          Vnode *parentptr,
1364                          Volume *volptr,
1365                          afs_size_t length)
1366 {
1367 #if FS_STATS_DETAILED
1368     Date currDate;              /*Current date*/
1369     int writeIdx;               /*Write index to bump*/
1370     int timeIdx;                /*Authorship time index to bump*/
1371 #endif /* FS_STATS_DETAILED */
1372
1373     if (Caller & (TVS_CFILE|TVS_SLINK|TVS_MKDIR))       {   /* initialize new file */
1374         targetptr->disk.parent = parentptr->vnodeNumber;
1375         VN_SET_LEN(targetptr, length);
1376         /* targetptr->disk.group =      0;  save some cycles */
1377         targetptr->disk.modeBits = 0777;
1378         targetptr->disk.owner = client->ViceId;
1379         targetptr->disk.dataVersion =  0 ; /* consistent with the client */
1380         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1381         /* the inode was created in Alloc_NewVnode() */
1382     }
1383
1384 #if FS_STATS_DETAILED
1385     /*
1386      * Update file write stats for this volume.  Note that the auth
1387      * counter is located immediately after its associated ``distance''
1388      * counter.
1389      */
1390     if (client->InSameNetwork)
1391         writeIdx = VOL_STATS_SAME_NET;
1392     else
1393         writeIdx = VOL_STATS_DIFF_NET;
1394     V_stat_writes(volptr, writeIdx)++;
1395     if (client->ViceId != AnonymousID) {
1396         V_stat_writes(volptr, writeIdx+1)++;
1397     }
1398
1399     /*
1400      * We only count operations that DON'T involve creating new objects
1401      * (files, symlinks, directories) or simply setting status as
1402      * authorship-change operations.
1403      */
1404     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1405         /*
1406          * Update the volume's authorship information in response to this
1407          * file operation.  Get the current time, decide to which time
1408          * slot this operation belongs, and bump the appropriate slot.
1409          */
1410         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1411         timeIdx = (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 :
1412                    currDate < VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 :
1413                    currDate < VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 :
1414                    currDate < VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 :
1415                    currDate < VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1416                    VOL_STATS_TIME_IDX_5);
1417         if (targetptr->disk.author == client->ViceId) {
1418             V_stat_fileSameAuthor(volptr, timeIdx)++;
1419         } else {
1420             V_stat_fileDiffAuthor(volptr, timeIdx)++;
1421         }
1422       }
1423 #endif /* FS_STATS_DETAILED */
1424
1425     if (!(Caller & TVS_SSTATUS))
1426       targetptr->disk.author = client->ViceId;
1427     if (Caller & TVS_SDATA) {
1428       targetptr->disk.dataVersion++;
1429       if (VanillaUser(client))
1430         {
1431           targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1432 #ifdef CREATE_SGUID_ADMIN_ONLY
1433           targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1434 #endif
1435         }
1436     }
1437     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1438         /* store status, must explicitly request to change the date */
1439         if (InStatus->Mask & AFS_SETMODTIME)
1440             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1441     }
1442     else {/* other: date always changes, but perhaps to what is specified by caller */
1443         targetptr->disk.unixModifyTime = (InStatus->Mask & AFS_SETMODTIME ? InStatus->ClientModTime : FT_ApproxTime());
1444     }
1445     if (InStatus->Mask & AFS_SETOWNER) {
1446         /* admin is allowed to do chmod, chown as well as chown, chmod. */
1447         if (VanillaUser(client))
1448           {
1449             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1450 #ifdef CREATE_SGUID_ADMIN_ONLY
1451             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1452 #endif
1453           }
1454         targetptr->disk.owner = InStatus->Owner;
1455         if (VolumeRootVnode (targetptr)) {
1456             Error errorCode = 0;        /* what should be done with this? */
1457
1458             V_owner(targetptr->volumePtr) = InStatus->Owner;
1459             VUpdateVolume(&errorCode, targetptr->volumePtr);
1460         }
1461     }
1462     if (InStatus->Mask & AFS_SETMODE) {
1463         int modebits = InStatus->UnixModeBits;
1464 #define CREATE_SGUID_ADMIN_ONLY 1
1465 #ifdef CREATE_SGUID_ADMIN_ONLY
1466         if (VanillaUser(client)) 
1467             modebits = modebits & 0777;
1468 #endif
1469         if (VanillaUser(client)) {
1470           targetptr->disk.modeBits = modebits;
1471         }
1472         else {
1473           targetptr->disk.modeBits = modebits;
1474           switch ( Caller ) {
1475           case TVS_SDATA: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1476                                     AUD_INT, CHK_STOREDATA, AUD_END); break;
1477           case TVS_CFILE:
1478           case TVS_SSTATUS: osi_audit( PrivSetID, 0, AUD_INT, client->ViceId,
1479                                     AUD_INT, CHK_STORESTATUS, AUD_END); break;
1480           default: break;
1481           }
1482         }
1483       }
1484     targetptr->disk.serverModifyTime = FT_ApproxTime();
1485     if (InStatus->Mask & AFS_SETGROUP)
1486         targetptr->disk.group = InStatus->Group;
1487     /* vnode changed : to be written back by VPutVnode */
1488     targetptr->changed_newTime = 1;
1489
1490 } /*Update_TargetVnodeStatus*/
1491
1492
1493 /*
1494  * Fills the CallBack structure with the expiration time and type of callback
1495  * structure. Warning: this function is currently incomplete.
1496  */
1497 static void
1498 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1499 {
1500     /* CallBackTime could not be 0 */
1501     if (CallBackTime == 0) {
1502         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1503         CallBack->ExpirationTime = 0;
1504     } else
1505         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();      
1506     CallBack->CallBackVersion = CALLBACK_VERSION;
1507     CallBack->CallBackType = CB_SHARED;             /* The default for now */
1508
1509 } /*SetCallBackStruct*/
1510
1511
1512 /*
1513  * Adjusts (Subtract) "length" number of blocks from the volume's disk
1514  * allocation; if some error occured (exceeded volume quota or partition
1515  * was full, or whatever), it frees the space back and returns the code.
1516  * We usually pre-adjust the volume space to make sure that there's
1517  * enough space before consuming some.
1518  */
1519 static afs_int32
1520 AdjustDiskUsage(Volume *volptr, afs_size_t length, afs_size_t checkLength)
1521 {
1522     int rc;
1523     int nc;
1524
1525     VAdjustDiskUsage(&rc, volptr, length, checkLength);
1526     if (rc) {
1527         VAdjustDiskUsage(&nc, volptr, -length, (afs_size_t) 0);
1528         if (rc == VOVERQUOTA) {
1529             ViceLog(2,("Volume %u (%s) is full\n",
1530                     V_id(volptr), V_name(volptr)));
1531             return(rc);
1532         }
1533         if (rc == VDISKFULL) {
1534             ViceLog(0,("Partition %s that contains volume %u is full\n",
1535                     volptr->partition->name, V_id(volptr)));
1536             return(rc);
1537         }
1538         ViceLog(0,("Got error return %d from VAdjustDiskUsage\n",rc));
1539         return(rc);
1540     }
1541     return(0);
1542
1543 } /*AdjustDiskUsage*/
1544
1545 /*
1546  * Common code that handles the creation of a new file (SAFS_CreateFile and
1547  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1548  */
1549 static afs_int32
1550 Alloc_NewVnode(Vnode *parentptr,
1551                DirHandle *dir,
1552                Volume *volptr,
1553                Vnode **targetptr,
1554                char *Name,
1555                struct AFSFid *OutFid,
1556                int FileType,
1557                afs_size_t BlocksPreallocatedForVnode)
1558 {
1559     int errorCode = 0;          /* Error code returned back */
1560     int temp;
1561     Inode inode=0;
1562     Inode nearInode;            /* hint for inode allocation in solaris */
1563
1564     if ((errorCode = AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1565                                     BlocksPreallocatedForVnode))) {
1566         ViceLog(25, ("Insufficient space to allocate %d blocks\n", 
1567                      BlocksPreallocatedForVnode));
1568         return(errorCode);
1569     }
1570
1571     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1572     if (errorCode != 0) {
1573         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode,
1574                          (afs_size_t) 0);
1575         return(errorCode);
1576     }
1577     OutFid->Volume = V_id(volptr);
1578     OutFid->Vnode = (*targetptr)->vnodeNumber;
1579     OutFid->Unique = (*targetptr)->disk.uniquifier;
1580
1581     nearInode = VN_GET_INO(parentptr);   /* parent is also in same vol */
1582
1583     /* create the inode now itself */
1584     inode = IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1585                       VPartitionPath(V_partition(volptr)), nearInode,
1586                       V_id(volptr), (*targetptr)->vnodeNumber,
1587                       (*targetptr)->disk.uniquifier, 1);
1588
1589     /* error in creating inode */
1590     if (!VALID_INO(inode)) 
1591     {
1592                ViceLog(0, ("Volume : %d vnode = %d Failed to create inode: errno = %d\n", 
1593                          (*targetptr)->volumePtr->header->diskstuff.id,
1594                          (*targetptr)->vnodeNumber, 
1595                          errno));
1596                 VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode,
1597                                  (afs_size_t) 0);
1598                 (*targetptr)->delete = 1; /* delete vnode */
1599                 return ENOSPC;
1600     }
1601     VN_SET_INO(*targetptr, inode);
1602     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1603
1604     /* copy group from parent dir */
1605     (*targetptr)->disk.group = parentptr->disk.group;
1606
1607     if (parentptr->disk.cloned) 
1608     {
1609         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1610         if ((errorCode = CopyOnWrite(parentptr, volptr)))  /* disk full */
1611         {
1612                 ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1613                 /* delete the vnode previously allocated */
1614                 (*targetptr)->delete = 1;
1615                 VAdjustDiskUsage(&temp, volptr,
1616                                  -BlocksPreallocatedForVnode, (afs_size_t) 0);
1617                 IH_REALLYCLOSE((*targetptr)->handle);
1618                 if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)) )
1619                     ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1620                                 volptr->partition->name,
1621                                PrintInode(NULL, inode)));
1622                 IH_RELEASE((*targetptr)->handle);
1623                         
1624                 return errorCode;
1625         }
1626     }
1627     
1628     /* add the name to the directory */
1629     SetDirHandle(dir, parentptr);
1630     if ((errorCode = Create(dir,(char *)Name, OutFid))) {
1631         (*targetptr)->delete = 1;
1632         VAdjustDiskUsage(&temp, volptr, - BlocksPreallocatedForVnode,
1633                          (afs_size_t) 0);
1634         IH_REALLYCLOSE((*targetptr)->handle);
1635         if ( IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1636             ViceLog(0,("Alloc_NewVnode: partition %s idec %s failed\n",
1637                        volptr->partition->name,
1638                        PrintInode(NULL, inode)));
1639         IH_RELEASE((*targetptr)->handle);
1640         return(errorCode);
1641     }
1642     DFlush();
1643     return(0);
1644
1645 } /*Alloc_NewVnode*/
1646
1647
1648 /*
1649  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1650  * SAFS_ReleaseLock)
1651  */
1652 static afs_int32
1653 HandleLocking(Vnode *targetptr, afs_int32 rights, ViceLockType LockingType)
1654 {
1655     int Time;           /* Used for time */
1656     int writeVnode = targetptr->changed_oldTime; /* save original status */
1657
1658     /* Does the caller has Lock priviledges; root extends locks, however */
1659     if (LockingType != LockExtend && !(rights & PRSFS_LOCK))
1660         return(EACCES);
1661     targetptr->changed_oldTime = 1; /* locking doesn't affect any time stamp */
1662     Time = FT_ApproxTime();
1663     switch (LockingType) {
1664         case LockRead:
1665         case LockWrite:
1666             if (Time > targetptr->disk.lock.lockTime)
1667                 targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount = 0;
1668             Time += AFS_LOCKWAIT;
1669             if (LockingType == LockRead) {
1670                 if (targetptr->disk.lock.lockCount >= 0) {
1671                     ++(targetptr->disk.lock.lockCount);
1672                     targetptr->disk.lock.lockTime = Time;
1673                 } else return(EAGAIN);
1674             } else {
1675                 if (targetptr->disk.lock.lockCount == 0) {
1676                     targetptr->disk.lock.lockCount = -1;
1677                     targetptr->disk.lock.lockTime = Time;
1678                 } else return(EAGAIN);
1679             }
1680             break;
1681         case LockExtend:
1682             Time += AFS_LOCKWAIT;
1683             if (targetptr->disk.lock.lockCount != 0)
1684                 targetptr->disk.lock.lockTime = Time;
1685             else return(EINVAL);            
1686             break;
1687         case LockRelease:
1688             if ((--targetptr->disk.lock.lockCount) <= 0)
1689                 targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime = 0;
1690             break;
1691         default:
1692             targetptr->changed_oldTime = writeVnode; /* restore old status */
1693             ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1694     }
1695     return(0);
1696 } /*HandleLocking*/
1697
1698 /* 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. */
1699
1700 static afs_int32
1701 CheckWriteMode(Vnode *targetptr, afs_int32 rights, int Prfs_Mode)
1702 {
1703     if (readonlyServer)
1704         return(VREADONLY);
1705     if (!(rights & Prfs_Mode))
1706         return(EACCES);
1707     if ((targetptr->disk.type != vDirectory) && (!(targetptr->disk.modeBits & OWNERWRITE)))
1708         return(EACCES);
1709     return(0);
1710 }
1711
1712 /*
1713  * If some flags (i.e. min or max quota) are set, the volume's in disk
1714  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1715  * update, if applicable.
1716  */
1717 static afs_int32
1718 RXUpdate_VolumeStatus(Volume *volptr, AFSStoreVolumeStatus* StoreVolStatus,
1719                       char *Name, char *OfflineMsg, char *Motd)
1720 {
1721     Error errorCode = 0;
1722
1723     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1724         V_minquota(volptr) = StoreVolStatus->MinQuota;
1725     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1726         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1727     if (strlen(OfflineMsg) > 0) {
1728         strcpy(V_offlineMessage(volptr), OfflineMsg);
1729     }
1730     if (strlen(Name) > 0) {
1731         strcpy(V_name(volptr), Name);
1732     }
1733 #if TRANSARC_VOL_STATS
1734     /*
1735      * We don't overwrite the motd field, since it's now being used
1736      * for stats
1737      */
1738 #else
1739     if (strlen(Motd) > 0) {
1740         strcpy(V_motd(volptr), Motd);
1741     }
1742 #endif /* FS_STATS_DETAILED */
1743     VUpdateVolume(&errorCode, volptr);
1744     return(errorCode);
1745
1746 } /*RXUpdate_VolumeStatus*/
1747
1748
1749 /* old interface */
1750 static afs_int32
1751 Update_VolumeStatus(Volume *volptr, VolumeStatus *StoreVolStatus,
1752                     struct BBS *Name, struct BBS *OfflineMsg,
1753                     struct BBS *Motd)
1754 {
1755     Error errorCode = 0;
1756
1757     if (StoreVolStatus->MinQuota > -1)
1758         V_minquota(volptr) = StoreVolStatus->MinQuota;
1759     if (StoreVolStatus->MaxQuota > -1)
1760         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1761     if (OfflineMsg->SeqLen > 1)
1762         strcpy(V_offlineMessage(volptr), OfflineMsg->SeqBody);
1763     if (Name->SeqLen > 1)
1764         strcpy(V_name(volptr), Name->SeqBody);
1765 #if TRANSARC_VOL_STATS
1766     /*
1767      * We don't overwrite the motd field, since it's now being used
1768      * for stats
1769      */
1770 #else
1771     if (Motd->SeqLen > 1)
1772         strcpy(V_motd(volptr), Motd->SeqBody);
1773 #endif /* FS_STATS_DETAILED */
1774     VUpdateVolume(&errorCode, volptr);
1775     return(errorCode);
1776
1777 } /*Update_VolumeStatus*/
1778
1779
1780 /*
1781  * Get internal volume-related statistics from the Volume disk label
1782  * structure and put it into the VolumeStatus structure, status; it's
1783  * used by both SAFS_GetVolumeStatus and SAFS_SetVolumeStatus to return
1784  * the volume status to the caller.
1785  */
1786 static afs_int32
1787 GetVolumeStatus(VolumeStatus *status, struct BBS *name, struct BBS *offMsg,
1788                 struct BBS *motd, Volume *volptr)
1789 {
1790     status->Vid = V_id(volptr);
1791     status->ParentId = V_parentId(volptr);
1792     status->Online = V_inUse(volptr);
1793     status->InService = V_inService(volptr);
1794     status->Blessed = V_blessed(volptr);
1795     status->NeedsSalvage = V_needsSalvaged(volptr);
1796     if (VolumeWriteable(volptr))
1797         status->Type = ReadWrite;
1798     else
1799         status->Type = ReadOnly;
1800     status->MinQuota = V_minquota(volptr);
1801     status->MaxQuota = V_maxquota(volptr);
1802     status->BlocksInUse = V_diskused(volptr);
1803     status->PartBlocksAvail = volptr->partition->free;
1804     status->PartMaxBlocks = volptr->partition->totalUsable;
1805     strncpy(name->SeqBody, V_name(volptr), (int)name->MaxSeqLen);
1806     name->SeqLen = strlen(V_name(volptr)) + 1;
1807     if (name->SeqLen > name->MaxSeqLen) name->SeqLen = name -> MaxSeqLen;
1808     strncpy(offMsg->SeqBody, V_offlineMessage(volptr), (int)name->MaxSeqLen);
1809     offMsg->SeqLen = strlen(V_offlineMessage(volptr)) + 1;
1810     if (offMsg->SeqLen > offMsg->MaxSeqLen)
1811         offMsg->SeqLen = offMsg -> MaxSeqLen;
1812 #ifdef notdef
1813     /*Don't do anything with the motd field*/
1814     strncpy(motd->SeqBody, nullString, (int)offMsg->MaxSeqLen);
1815     motd->SeqLen = strlen(nullString) + 1;
1816 #endif
1817     if (motd->SeqLen > motd->MaxSeqLen)
1818         motd->SeqLen = motd -> MaxSeqLen;
1819
1820 } /*GetVolumeStatus*/
1821
1822 static afs_int32
1823 RXGetVolumeStatus(AFSFetchVolumeStatus *status, char **name, char **offMsg,
1824                   char **motd, Volume *volptr)
1825 {
1826     int temp;
1827
1828     status->Vid = V_id(volptr);
1829     status->ParentId = V_parentId(volptr);
1830     status->Online = V_inUse(volptr);
1831     status->InService = V_inService(volptr);
1832     status->Blessed = V_blessed(volptr);
1833     status->NeedsSalvage = V_needsSalvaged(volptr);
1834     if (VolumeWriteable(volptr))
1835         status->Type = ReadWrite;
1836     else
1837         status->Type = ReadOnly;
1838     status->MinQuota = V_minquota(volptr);
1839     status->MaxQuota = V_maxquota(volptr);
1840     status->BlocksInUse = V_diskused(volptr);
1841     status->PartBlocksAvail = volptr->partition->free;
1842     status->PartMaxBlocks = volptr->partition->totalUsable;
1843
1844     /* now allocate and copy these things; they're freed by the RXGEN stub */
1845     temp = strlen(V_name(volptr)) + 1;
1846     *name = malloc(temp);
1847     if (!*name) {
1848         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1849         assert(0);
1850     }
1851     strcpy(*name, V_name(volptr));
1852     temp = strlen(V_offlineMessage(volptr)) + 1;
1853     *offMsg = malloc(temp);
1854     if (!*offMsg) {
1855         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1856         assert(0);
1857     }
1858     strcpy(*offMsg, V_offlineMessage(volptr));
1859 #if TRANSARC_VOL_STATS
1860     *motd = malloc(1);
1861     if (!*motd) {
1862         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1863         assert(0);
1864     }
1865     strcpy(*motd, nullString);
1866 #else
1867     temp = strlen(V_motd(volptr)) + 1;
1868     *motd = malloc(temp);
1869     if (!*motd) {
1870         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1871         assert(0);
1872     }
1873     strcpy(*motd, V_motd(volptr));
1874 #endif /* FS_STATS_DETAILED */
1875
1876 } /*RXGetVolumeStatus*/
1877
1878
1879 static afs_int32
1880 FileNameOK(register char *aname)
1881 {
1882     register afs_int32 i, tc;
1883     i = strlen(aname);
1884     if (i >= 4) {
1885         /* watch for @sys on the right */
1886         if (strcmp(aname+i-4, "@sys") == 0) return 0;
1887     }
1888     while ((tc = *aname++)) {
1889         if (tc == '/') return 0;    /* very bad character to encounter */
1890     }
1891     return 1;   /* file name is ok */
1892
1893 } /*FileNameOK*/
1894
1895
1896 /* Debugging tool to print Volume Statu's contents */
1897 static void
1898 PrintVolumeStatus(VolumeStatus *status)
1899 {
1900     ViceLog(5,("Volume header contains:\n"));
1901     ViceLog(5,("Vid = %u, Parent = %u, Online = %d, InService = %d, Blessed = %d, NeedsSalvage = %d\n",
1902             status->Vid, status->ParentId, status->Online, status->InService,
1903             status->Blessed, status->NeedsSalvage));
1904     ViceLog(5,("MinQuota = %d, MaxQuota = %d\n", status->MinQuota, status->MaxQuota));
1905     ViceLog(5,("Type = %d, BlocksInUse = %d, PartBlocksAvail = %d, PartMaxBlocks = %d\n",
1906             status->Type, status->BlocksInUse, status->PartBlocksAvail, status->PartMaxBlocks));
1907
1908 } /*PrintVolumeStatus*/
1909
1910
1911 /*
1912  * This variant of symlink is expressly to support the AFS/DFS translator
1913  * and is not supported by the AFS fileserver. We just return EINVAL.
1914  * The cache manager should not generate this call to an AFS cache manager.
1915  */
1916 afs_int32 SRXAFS_DFSSymlink (struct rx_call *acall,
1917                              struct AFSFid *DirFid,
1918                              char *Name,
1919                              char *LinkContents,
1920                              struct AFSStoreStatus *InStatus,
1921                              struct AFSFid *OutFid,
1922                              struct AFSFetchStatus *OutFidStatus,
1923                              struct AFSFetchStatus *OutDirStatus,
1924                              struct AFSCallBack *CallBack,
1925                              struct AFSVolSync *Sync)
1926 {
1927     return EINVAL;
1928 }
1929
1930 afs_int32 SRXAFS_ResidencyCmd (struct rx_call *acall, struct AFSFid *Fid,
1931                                struct ResidencyCmdInputs *Inputs,
1932                                struct ResidencyCmdOutputs *Outputs)
1933 {
1934     return EINVAL;
1935 }
1936
1937 static struct afs_buffer {
1938     struct afs_buffer *next;
1939 } *freeBufferList = 0;
1940 static int afs_buffersAlloced = 0;
1941
1942 static FreeSendBuffer(register struct afs_buffer *adata)
1943 {
1944     FS_LOCK
1945     afs_buffersAlloced--;
1946     adata->next = freeBufferList;
1947     freeBufferList = adata;
1948     FS_UNLOCK
1949     return 0;
1950
1951 } /*FreeSendBuffer*/
1952
1953 /* allocate space for sender */
1954 static char *AllocSendBuffer()
1955 {
1956     register struct afs_buffer *tp;
1957
1958     FS_LOCK
1959     afs_buffersAlloced++;
1960     if (!freeBufferList) {
1961         char *tmp;
1962         FS_UNLOCK
1963
1964         tmp = malloc(sendBufSize);
1965         if (!tmp) {
1966             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1967             assert(0);
1968         }
1969         return tmp;
1970     }
1971     tp = freeBufferList;
1972     freeBufferList = tp->next;
1973     FS_UNLOCK
1974     return (char *) tp;
1975
1976 } /*AllocSendBuffer*/
1977
1978 /*
1979  * This routine returns the status info associated with the targetptr vnode
1980  * in the AFSFetchStatus structure.  Some of the newer fields, such as
1981  * SegSize and Group are not yet implemented
1982  */
1983 static 
1984 void GetStatus(Vnode *targetptr,
1985                AFSFetchStatus *status,
1986                afs_int32 rights,
1987                afs_int32 anyrights,
1988                Vnode *parentptr)
1989 {
1990     /* initialize return status from a vnode  */
1991     status->InterfaceVersion = 1;
1992     status->SyncCounter = status->dataVersionHigh = status->lockCount =
1993     status->errorCode = 0;
1994     status->ResidencyMask = 1; /* means for MR-AFS: file in /vicepr-partition */
1995     if (targetptr->disk.type == vFile)
1996         status->FileType = File;
1997     else if (targetptr->disk.type == vDirectory)
1998         status->FileType = Directory;
1999     else if (targetptr->disk.type == vSymlink)
2000         status->FileType = SymbolicLink;
2001     else
2002         status->FileType = Invalid;                     /*invalid type field */
2003     status->LinkCount = targetptr->disk.linkCount;
2004     SET_STATUS_LEN(status, targetptr);
2005     status->DataVersion = targetptr->disk.dataVersion;
2006     status->Author = targetptr->disk.author;
2007     status->Owner = targetptr->disk.owner;
2008     status->CallerAccess = rights;
2009     status->AnonymousAccess = anyrights;
2010     status->UnixModeBits = targetptr->disk.modeBits;
2011     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2012     status->ParentVnode = (status->FileType == Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2013     status->ParentUnique = (status->FileType == Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2014     status->ServerModTime = targetptr->disk.serverModifyTime;                   
2015     status->Group = targetptr->disk.group;
2016     status->lockCount = targetptr->disk.lock.lockCount;
2017     status->errorCode = 0;
2018
2019 } /*GetStatus*/
2020
2021 static
2022 afs_int32 common_FetchData64 (struct rx_call *acall, 
2023                               struct AFSFid *Fid,    
2024                               afs_size_t Pos,         
2025                               afs_size_t Len,         
2026                               struct AFSFetchStatus *OutStatus,
2027                               struct AFSCallBack *CallBack,
2028                               struct AFSVolSync *Sync,
2029                               int type)              
2030
2031     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
2032     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
2033     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
2034     int     errorCode = 0;                  /* return code to caller */
2035     int     fileCode =  0;                  /* return code from vol package */
2036     Volume * volptr = 0;                    /* pointer to the volume */
2037     struct client *client;                  /* pointer to the client data */
2038     struct rx_connection *tcon;             /* the connection we're part of */
2039     afs_int32 rights, anyrights;                    /* rights for this and any user */
2040     struct client *t_client;                /* tmp ptr to client data */
2041     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2042 #if FS_STATS_DETAILED
2043     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2044     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2045     struct timeval opStartTime,
2046                    opStopTime;              /* Start/stop times for RPC op*/
2047     struct timeval xferStartTime,
2048                    xferStopTime;            /* Start/stop times for xfer portion*/
2049     struct timeval elapsedTime;             /* Transfer time */
2050     afs_size_t bytesToXfer;                         /* # bytes to xfer*/
2051     afs_size_t bytesXferred;                        /* # bytes actually xferred*/
2052     int readIdx;                            /* Index of read stats array to bump*/
2053     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2054
2055     /*
2056      * Set our stats pointers, remember when the RPC operation started, and
2057      * tally the operation.
2058      */
2059     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2060     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2061     FS_LOCK
2062     (opP->numOps)++;
2063     FS_UNLOCK
2064     TM_GetTimeOfDay(&opStartTime, 0);
2065 #endif /* FS_STATS_DETAILED */
2066
2067     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
2068             Fid->Volume, Fid->Vnode, Fid->Unique));     
2069     FS_LOCK
2070     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2071     FS_UNLOCK
2072
2073     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
2074         goto Bad_FetchData;
2075
2076     /* Get ptr to client data for user Id for logging */
2077     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2078     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2079     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
2080             Fid->Volume, Fid->Vnode, Fid->Unique,
2081             inet_ntoa(logHostAddr), t_client->ViceId)); 
2082     /*
2083      * Get volume/vnode for the fetched file; caller's access rights to
2084      * it are also returned
2085      */
2086     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2087                                      DONTCHECK, &parentwhentargetnotdir,
2088                                      &client, READ_LOCK, &rights, &anyrights)))
2089         goto Bad_FetchData;
2090
2091     SetVolumeSync(Sync, volptr);
2092
2093 #if FS_STATS_DETAILED
2094     /*
2095      * Remember that another read operation was performed.
2096      */
2097     FS_LOCK
2098     if (client->InSameNetwork)
2099         readIdx = VOL_STATS_SAME_NET;
2100     else
2101         readIdx = VOL_STATS_DIFF_NET;
2102     V_stat_reads(volptr, readIdx)++;
2103     if (client->ViceId != AnonymousID) {
2104         V_stat_reads(volptr, readIdx+1)++;
2105     }
2106     FS_UNLOCK
2107 #endif /* FS_STATS_DETAILED */
2108
2109     /* Check whether the caller has permission access to fetch the data */
2110     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2111                                            CHK_FETCHDATA, 0))) 
2112         goto Bad_FetchData;
2113
2114     /*
2115      * Drop the read lock on the parent directory after saving the parent
2116      * vnode information we need to pass to GetStatus
2117      */
2118     if (parentwhentargetnotdir != NULL) {
2119         tparentwhentargetnotdir = *parentwhentargetnotdir;
2120         VPutVnode(&fileCode, parentwhentargetnotdir);
2121         assert(!fileCode || (fileCode == VSALVAGE));
2122         parentwhentargetnotdir = NULL;
2123     }
2124
2125 #if FS_STATS_DETAILED
2126     /*
2127      * Remember when the data transfer started.
2128      */
2129     TM_GetTimeOfDay(&xferStartTime, 0);
2130 #endif /* FS_STATS_DETAILED */
2131
2132     /* actually do the data transfer */
2133 #if FS_STATS_DETAILED
2134     errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2135                                   (afs_size_t) Pos, (afs_size_t) Len, type,
2136                                   &bytesToXfer, &bytesXferred);
2137 #else
2138     if ((errorCode = FetchData_RXStyle(volptr, targetptr, acall,
2139                                        (afs_size_t) Pos, (afs_size_t) Len,
2140                                        type)))
2141         goto Bad_FetchData;
2142 #endif /* FS_STATS_DETAILED */
2143
2144 #if FS_STATS_DETAILED
2145     /*
2146      * At this point, the data transfer is done, for good or ill.  Remember
2147      * when the transfer ended, bump the number of successes/failures, and
2148      * integrate the transfer size and elapsed time into the stats.  If the
2149      * operation failed, we jump to the appropriate point.
2150      */
2151     TM_GetTimeOfDay(&xferStopTime, 0);
2152     FS_LOCK
2153     (xferP->numXfers)++;
2154     if (!errorCode) {
2155         (xferP->numSuccesses)++;
2156
2157         /*
2158          * Bump the xfer sum by the number of bytes actually sent, NOT the
2159          * target number.
2160          */
2161         tot_bytesXferred += bytesXferred;
2162         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2163         tot_bytesXferred &= 0x3FF;
2164         if (bytesXferred < xferP->minBytes)
2165             xferP->minBytes = bytesXferred;
2166         if (bytesXferred > xferP->maxBytes)
2167             xferP->maxBytes = bytesXferred;
2168
2169         /*
2170          * Tally the size of the object.  Note: we tally the actual size,
2171          * NOT the number of bytes that made it out over the wire.
2172          */
2173         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2174             (xferP->count[0])++;
2175         else
2176             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2177                 (xferP->count[1])++;
2178         else
2179             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2180                 (xferP->count[2])++;
2181         else
2182             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2183                 (xferP->count[3])++;
2184         else
2185             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2186                 (xferP->count[4])++;
2187         else
2188             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2189                 (xferP->count[5])++;
2190         else
2191             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2192                 (xferP->count[6])++;
2193         else
2194             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2195                 (xferP->count[7])++;
2196         else
2197             (xferP->count[8])++;
2198
2199         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2200         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2201         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2202         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2203             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2204         }
2205         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2206             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2207         }
2208       }
2209     FS_UNLOCK
2210     /*
2211      * Finally, go off to tell our caller the bad news in case the
2212      * fetch failed.
2213      */
2214     if (errorCode)
2215         goto Bad_FetchData;
2216 #endif /* FS_STATS_DETAILED */
2217
2218     /* write back  the OutStatus from the target vnode  */
2219     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
2220
2221     /* if a r/w volume, promise a callback to the caller */
2222     if (VolumeWriteable(volptr))
2223         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2224     else {
2225       struct AFSFid myFid;              
2226       memset(&myFid, 0, sizeof(struct AFSFid));
2227       myFid.Volume = Fid->Volume;
2228       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2229       }
2230
2231 Bad_FetchData: 
2232     /* Update and store volume/vnode and parent vnodes back */
2233     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2234     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
2235     CallPostamble(tcon);
2236
2237 #if FS_STATS_DETAILED
2238     TM_GetTimeOfDay(&opStopTime, 0);
2239     if (errorCode == 0) {
2240         FS_LOCK
2241         (opP->numSuccesses)++;
2242         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2243         fs_stats_AddTo((opP->sumTime), elapsedTime);
2244         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2245         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2246             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2247         }
2248         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2249             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2250         }
2251         FS_UNLOCK
2252       }
2253
2254 #endif /* FS_STATS_DETAILED */
2255
2256     osi_auditU (acall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
2257     return(errorCode);
2258
2259 } /*common_FetchData64*/
2260
2261 afs_int32 SRXAFS_FetchData (struct rx_call *acall,   
2262                             struct AFSFid *Fid,      
2263                             afs_int32 Pos,           
2264                             afs_int32 Len,           
2265                             struct AFSFetchStatus *OutStatus,
2266                             struct AFSCallBack *CallBack, 
2267                             struct AFSVolSync *Sync) 
2268
2269 {
2270     int code;
2271
2272     code = common_FetchData64 (acall, Fid,
2273                                (afs_size_t) Pos, (afs_size_t) Len,
2274                                OutStatus,
2275                                CallBack, Sync, 0);
2276     return code;
2277 }
2278
2279 afs_int32 SRXAFS_FetchData64 (struct rx_call *acall, 
2280                               struct AFSFid *Fid,    
2281                               afs_int64 Pos,         
2282                               afs_int64 Len,         
2283                               struct AFSFetchStatus *OutStatus,
2284                               struct AFSCallBack *CallBack,
2285                               struct AFSVolSync *Sync)
2286 {
2287     int code;
2288     afs_size_t tPos, tLen;
2289
2290 #ifdef AFS_64BIT_ENV
2291 #ifndef AFS_LARGEFILE_ENV
2292     if (Pos + Len > 0x7fffffff)
2293         return E2BIG;
2294 #endif  /* !AFS_LARGEFILE_ENV */
2295     tPos = Pos;
2296     tLen = Len;
2297 #else /* AFS_64BIT_ENV */
2298     if (Pos.high || Len.high)
2299         return E2BIG;
2300     tPos = Pos.low;
2301     tLen = Len.low;
2302 #endif /* AFS_64BIT_ENV */
2303
2304     code = common_FetchData64 (acall, Fid, tPos, tLen, OutStatus,
2305                              CallBack, Sync, 1);
2306     return code;
2307 }
2308
2309 afs_int32 SRXAFS_FetchACL (struct rx_call *acall,    
2310                            struct AFSFid *Fid,       
2311                            struct AFSOpaque *AccessList,     
2312                            struct AFSFetchStatus *OutStatus, 
2313                            struct AFSVolSync *Sync)
2314 {
2315     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2316     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2317     int     errorCode = 0;              /* return error code to caller */
2318     Volume * volptr = 0;                /* pointer to the volume */
2319     struct client *client;              /* pointer to the client data */
2320     afs_int32 rights, anyrights;                /* rights for this and any user */
2321     struct rx_connection *tcon = rx_ConnectionOf(acall);
2322     struct client *t_client;                /* tmp ptr to client data */
2323     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2324 #if FS_STATS_DETAILED
2325     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2326     struct timeval opStartTime,
2327                    opStopTime;              /* Start/stop times for RPC op*/
2328     struct timeval elapsedTime;             /* Transfer time */
2329
2330     /*
2331      * Set our stats pointer, remember when the RPC operation started, and
2332      * tally the operation.
2333      */
2334     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2335     FS_LOCK
2336     (opP->numOps)++;
2337     FS_UNLOCK
2338     TM_GetTimeOfDay(&opStartTime, 0);
2339 #endif /* FS_STATS_DETAILED */
2340
2341     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
2342             Fid->Volume, Fid->Vnode, Fid->Unique));
2343     FS_LOCK
2344     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2345     FS_UNLOCK
2346     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2347         goto Bad_FetchACL;
2348
2349     /* Get ptr to client data for user Id for logging */
2350     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2351     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2352     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
2353             Fid->Volume, Fid->Vnode, Fid->Unique,
2354             inet_ntoa(logHostAddr), t_client->ViceId));
2355
2356     AccessList->AFSOpaque_len = 0;
2357     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2358     if (!AccessList->AFSOpaque_val) {
2359         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2360         assert(0);
2361     }
2362
2363     /*
2364      * Get volume/vnode for the fetched file; caller's access rights to it
2365      * are also returned
2366      */
2367     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2368                                      DONTCHECK, &parentwhentargetnotdir,
2369                                      &client, READ_LOCK, &rights, &anyrights)))
2370         goto Bad_FetchACL;
2371
2372     SetVolumeSync(Sync, volptr);
2373
2374     /* Check whether we have permission to fetch the ACL */
2375     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2376                                            CHK_FETCHACL, 0)))
2377         goto Bad_FetchACL;
2378
2379     /* Get the Access List from the dir's vnode */
2380     if ((errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
2381                                        AccessList)))
2382         goto Bad_FetchACL;
2383
2384     /* Get OutStatus back From the target Vnode  */
2385     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2386
2387 Bad_FetchACL: 
2388     /* Update and store volume/vnode and parent vnodes back */
2389     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2390     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
2391             errorCode, AccessList->AFSOpaque_val));
2392     CallPostamble(tcon);
2393
2394 #if FS_STATS_DETAILED
2395     TM_GetTimeOfDay(&opStopTime, 0);
2396     if (errorCode == 0) {
2397         FS_LOCK
2398         (opP->numSuccesses)++;
2399         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2400         fs_stats_AddTo((opP->sumTime), elapsedTime);
2401         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2402         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2403             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2404         }
2405         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2406             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2407         }
2408         FS_UNLOCK
2409       }
2410
2411 #endif /* FS_STATS_DETAILED */
2412
2413     osi_auditU (acall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
2414     return errorCode;
2415 } /*SRXAFS_FetchACL*/
2416
2417
2418 /*
2419  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2420  * merged into it when possible.
2421  */
2422 static 
2423 afs_int32 SAFSS_FetchStatus (struct rx_call *acall,
2424                              struct AFSFid *Fid,  
2425                              struct AFSFetchStatus *OutStatus,
2426                              struct AFSCallBack *CallBack,      
2427                              struct AFSVolSync *Sync)           
2428 {
2429     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2430     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2431     int     errorCode = 0;              /* return code to caller */
2432     Volume * volptr = 0;                /* pointer to the volume */
2433     struct client *client;              /* pointer to the client data */
2434     afs_int32 rights, anyrights;                /* rights for this and any user */
2435     struct client *t_client;            /* tmp ptr to client data */
2436     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2437     struct rx_connection *tcon = rx_ConnectionOf(acall);
2438
2439     /* Get ptr to client data for user Id for logging */
2440     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
2441     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2442     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
2443             Fid->Volume, Fid->Vnode, Fid->Unique,
2444             inet_ntoa(logHostAddr), t_client->ViceId));
2445     FS_LOCK
2446     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2447     FS_UNLOCK
2448     /*
2449      * Get volume/vnode for the fetched file; caller's rights to it are
2450      * also returned
2451      */
2452     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2453                                      DONTCHECK, &parentwhentargetnotdir,
2454                                      &client, READ_LOCK, &rights, &anyrights)))
2455         goto Bad_FetchStatus;
2456
2457     /* set volume synchronization information */
2458     SetVolumeSync(Sync, volptr);
2459
2460     /* Are we allowed to fetch Fid's status? */
2461     if (targetptr->disk.type != vDirectory) {
2462       if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2463                                              CHK_FETCHSTATUS, 0))) {
2464           if (rx_GetCallAbortCode(acall) == errorCode) 
2465               rx_SetCallAbortCode(acall, 0);
2466           goto Bad_FetchStatus;
2467       }
2468     }
2469
2470     /* set OutStatus From the Fid  */
2471     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
2472
2473     /* If a r/w volume, also set the CallBack state */
2474     if (VolumeWriteable(volptr))
2475         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2476     else {
2477       struct AFSFid myFid;              
2478       memset(&myFid, 0, sizeof(struct AFSFid));
2479       myFid.Volume = Fid->Volume;
2480       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2481       }
2482
2483 Bad_FetchStatus: 
2484     /* Update and store volume/vnode and parent vnodes back */
2485     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2486     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
2487     return errorCode;
2488
2489 } /*SAFSS_FetchStatus*/
2490
2491
2492 afs_int32 SRXAFS_BulkStatus(struct rx_call *acall,
2493                             struct AFSCBFids *Fids,
2494                             struct AFSBulkStats *OutStats,
2495                             struct AFSCBs *CallBacks,
2496                             struct AFSVolSync *Sync)
2497 {
2498     register int i;
2499     afs_int32 nfiles;
2500     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2501     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2502     int     errorCode = 0;              /* return code to caller */
2503     Volume * volptr = 0;                /* pointer to the volume */
2504     struct client *client;              /* pointer to the client data */
2505     afs_int32 rights, anyrights;                /* rights for this and any user */
2506     register struct AFSFid *tfid;       /* file id we're dealing with now */
2507     struct rx_connection *tcon = rx_ConnectionOf(acall);
2508 #if FS_STATS_DETAILED
2509     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2510     struct timeval opStartTime,
2511                    opStopTime;              /* Start/stop times for RPC op*/
2512     struct timeval elapsedTime;             /* Transfer time */
2513
2514     /*
2515      * Set our stats pointer, remember when the RPC operation started, and
2516      * tally the operation.
2517      */
2518     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2519     FS_LOCK
2520     (opP->numOps)++;
2521     FS_UNLOCK
2522     TM_GetTimeOfDay(&opStartTime, 0);
2523 #endif /* FS_STATS_DETAILED */
2524
2525     ViceLog(1, ("SAFS_BulkStatus\n"));
2526     FS_LOCK
2527     AFSCallStats.TotalCalls++;
2528     FS_UNLOCK
2529
2530     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2531     if (nfiles <= 0) {                  /* Sanity check */
2532         errorCode = EINVAL;
2533         goto Audit_and_Return;
2534     }
2535
2536     /* allocate space for return output parameters */
2537     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2538         malloc(nfiles * sizeof(struct AFSFetchStatus));
2539     if (!OutStats->AFSBulkStats_val) {
2540         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2541         assert(0);
2542     }
2543     OutStats->AFSBulkStats_len = nfiles;
2544     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2545         malloc(nfiles * sizeof(struct AFSCallBack));
2546     if (!CallBacks->AFSCBs_val) {
2547         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2548         assert(0);
2549     }
2550     CallBacks->AFSCBs_len = nfiles;
2551
2552     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2553         goto Bad_BulkStatus;
2554
2555     tfid = Fids->AFSCBFids_val;
2556     for (i=0; i<nfiles; i++, tfid++) {
2557         /*
2558          * Get volume/vnode for the fetched file; caller's rights to it
2559          * are also returned
2560          */
2561         if ((errorCode =
2562             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2563                              DONTCHECK, &parentwhentargetnotdir, &client,
2564                              READ_LOCK, &rights, &anyrights)))
2565                 goto Bad_BulkStatus;
2566         /* set volume synchronization information, but only once per call */
2567         if (i == nfiles)
2568             SetVolumeSync(Sync, volptr);
2569
2570         /* Are we allowed to fetch Fid's status? */
2571         if (targetptr->disk.type != vDirectory) {
2572             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2573                                                    CHK_FETCHSTATUS, 0))) {
2574                 if (rx_GetCallAbortCode(acall) == errorCode) 
2575                     rx_SetCallAbortCode(acall, 0);
2576                 goto Bad_BulkStatus;
2577             }
2578         }
2579
2580         /* set OutStatus From the Fid  */
2581         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
2582                   rights, anyrights, parentwhentargetnotdir);
2583
2584         /* If a r/w volume, also set the CallBack state */
2585         if (VolumeWriteable(volptr))
2586             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2587                               &CallBacks->AFSCBs_val[i]);
2588         else {
2589           struct AFSFid myFid;          
2590           memset(&myFid, 0, sizeof(struct AFSFid));
2591           myFid.Volume = tfid->Volume;
2592           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2593                               &CallBacks->AFSCBs_val[i]);
2594         }
2595
2596         /* put back the file ID and volume */
2597         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2598         parentwhentargetnotdir = (Vnode *) 0;
2599         targetptr = (Vnode *) 0;
2600         volptr = (Volume *) 0;
2601     }
2602
2603 Bad_BulkStatus: 
2604     /* Update and store volume/vnode and parent vnodes back */
2605     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2606     CallPostamble(tcon);
2607
2608 #if FS_STATS_DETAILED
2609     TM_GetTimeOfDay(&opStopTime, 0);
2610     if (errorCode == 0) {
2611         FS_LOCK
2612         (opP->numSuccesses)++;
2613         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2614         fs_stats_AddTo((opP->sumTime), elapsedTime);
2615         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2616         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2617             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2618         }
2619         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2620             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2621         }
2622         FS_UNLOCK
2623     }   
2624
2625 #endif /* FS_STATS_DETAILED */
2626
2627 Audit_and_Return:
2628     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
2629     osi_auditU (acall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2630     return errorCode;
2631
2632 } /*SRXAFS_BulkStatus*/
2633
2634
2635 afs_int32 SRXAFS_InlineBulkStatus(struct rx_call *acall,
2636                                   struct AFSCBFids *Fids,
2637                                   struct AFSBulkStats *OutStats,
2638                                   struct AFSCBs *CallBacks,
2639                                   struct AFSVolSync *Sync)
2640 {
2641     register int i;
2642     afs_int32 nfiles;
2643     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
2644     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
2645     int     errorCode = 0;              /* return code to caller */
2646     Volume * volptr = 0;                /* pointer to the volume */
2647     struct client *client;              /* pointer to the client data */
2648     afs_int32 rights, anyrights;                /* rights for this and any user */
2649     register struct AFSFid *tfid;       /* file id we're dealing with now */
2650     struct rx_connection *tcon;
2651     AFSFetchStatus *tstatus;
2652 #if FS_STATS_DETAILED
2653     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2654     struct timeval opStartTime,
2655                    opStopTime;              /* Start/stop times for RPC op*/
2656     struct timeval elapsedTime;             /* Transfer time */
2657
2658     /*
2659      * Set our stats pointer, remember when the RPC operation started, and
2660      * tally the operation.
2661      */
2662     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2663     FS_LOCK
2664     (opP->numOps)++;
2665     FS_UNLOCK
2666     TM_GetTimeOfDay(&opStartTime, 0);
2667 #endif /* FS_STATS_DETAILED */
2668
2669     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2670     FS_LOCK
2671     AFSCallStats.TotalCalls++;
2672     FS_UNLOCK
2673
2674     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2675     if (nfiles <= 0) {                  /* Sanity check */
2676         errorCode = EINVAL;
2677         goto Audit_and_Return;
2678     }
2679
2680     /* allocate space for return output parameters */
2681     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2682         malloc(nfiles * sizeof(struct AFSFetchStatus));
2683     if (!OutStats->AFSBulkStats_val) {
2684         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2685         assert(0);
2686     }
2687     OutStats->AFSBulkStats_len = nfiles;
2688     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2689         malloc(nfiles * sizeof(struct AFSCallBack));
2690     if (!CallBacks->AFSCBs_val) {
2691         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2692         assert(0);
2693     }
2694     CallBacks->AFSCBs_len = nfiles;
2695
2696     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon))) {
2697         goto Bad_InlineBulkStatus;
2698     }
2699
2700     tfid = Fids->AFSCBFids_val;
2701     for (i=0; i<nfiles; i++, tfid++) {
2702         /*
2703          * Get volume/vnode for the fetched file; caller's rights to it
2704          * are also returned
2705          */
2706         if ((errorCode =
2707             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
2708                              DONTCHECK, &parentwhentargetnotdir, &client,
2709                              READ_LOCK, &rights, &anyrights))) {
2710             tstatus = &OutStats->AFSBulkStats_val[i];
2711             tstatus->errorCode = errorCode;
2712             parentwhentargetnotdir = (Vnode *) 0;
2713             targetptr = (Vnode *) 0;
2714             volptr = (Volume *) 0;
2715             continue;
2716         }
2717
2718         /* set volume synchronization information, but only once per call */
2719         if (i == nfiles)
2720             SetVolumeSync(Sync, volptr);
2721
2722         /* Are we allowed to fetch Fid's status? */
2723         if (targetptr->disk.type != vDirectory) {
2724             if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2725                                                    CHK_FETCHSTATUS, 0))) {
2726                 tstatus = &OutStats->AFSBulkStats_val[i];
2727                 tstatus->errorCode = errorCode;
2728                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2729                 parentwhentargetnotdir = (Vnode *) 0;
2730                 targetptr = (Vnode *) 0;
2731                 volptr = (Volume *) 0;
2732                 continue;
2733             }
2734         }
2735
2736         /* set OutStatus From the Fid  */
2737         GetStatus(targetptr, (struct AFSFetchStatus *) &OutStats->AFSBulkStats_val[i], 
2738           rights, anyrights, parentwhentargetnotdir);
2739
2740         /* If a r/w volume, also set the CallBack state */
2741         if (VolumeWriteable(volptr))
2742             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2743                               &CallBacks->AFSCBs_val[i]);
2744         else {
2745           struct AFSFid myFid;          
2746           memset(&myFid, 0, sizeof(struct AFSFid));
2747           myFid.Volume = tfid->Volume;
2748           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2749                               &CallBacks->AFSCBs_val[i]);
2750         }
2751
2752         /* put back the file ID and volume */
2753         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
2754         parentwhentargetnotdir = (Vnode *) 0;
2755         targetptr = (Vnode *) 0;
2756         volptr = (Volume *) 0;
2757     }
2758
2759 Bad_InlineBulkStatus: 
2760     /* Update and store volume/vnode and parent vnodes back */
2761     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
2762     CallPostamble(tcon);
2763
2764 #if FS_STATS_DETAILED
2765     TM_GetTimeOfDay(&opStopTime, 0);
2766     if (errorCode == 0) {
2767         FS_LOCK
2768         (opP->numSuccesses)++;
2769         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2770         fs_stats_AddTo((opP->sumTime), elapsedTime);
2771         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2772         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2773             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2774         }
2775         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2776             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2777         }
2778         FS_UNLOCK
2779     }   
2780
2781 #endif /* FS_STATS_DETAILED */
2782
2783 Audit_and_Return:
2784     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
2785     osi_auditU (acall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
2786     return 0;
2787
2788 } /*SRXAFS_InlineBulkStatus*/
2789
2790
2791 afs_int32 SRXAFS_FetchStatus (struct rx_call *acall,            
2792                               struct AFSFid *Fid,               
2793                               struct AFSFetchStatus *OutStatus, 
2794                               struct AFSCallBack *CallBack,     
2795                               struct AFSVolSync *Sync)
2796 {
2797     afs_int32 code;
2798     struct rx_connection *tcon;
2799 #if FS_STATS_DETAILED
2800     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2801     struct timeval opStartTime,
2802                    opStopTime;              /* Start/stop times for RPC op*/
2803     struct timeval elapsedTime;             /* Transfer time */
2804
2805     /*
2806      * Set our stats pointer, remember when the RPC operation started, and
2807      * tally the operation.
2808      */
2809     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2810     FS_LOCK
2811     (opP->numOps)++;
2812     FS_UNLOCK
2813     TM_GetTimeOfDay(&opStartTime, 0);
2814 #endif /* FS_STATS_DETAILED */
2815
2816     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
2817         goto Bad_FetchStatus;
2818
2819     code = SAFSS_FetchStatus (acall, Fid, OutStatus, CallBack, Sync);
2820
2821 Bad_FetchStatus:    
2822     CallPostamble(tcon);
2823
2824 #if FS_STATS_DETAILED
2825     TM_GetTimeOfDay(&opStopTime, 0);
2826     if (code == 0) {
2827         FS_LOCK
2828         (opP->numSuccesses)++;
2829         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2830         fs_stats_AddTo((opP->sumTime), elapsedTime);
2831         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2832         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2833             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2834         }
2835         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2836             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2837         }
2838         FS_UNLOCK
2839       }
2840
2841 #endif /* FS_STATS_DETAILED */
2842
2843     osi_auditU (acall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
2844     return code;
2845
2846 } /*SRXAFS_FetchStatus*/
2847
2848 static
2849 afs_int32 common_StoreData64 (struct rx_call *acall,
2850                               struct AFSFid *Fid,               
2851                               struct AFSStoreStatus *InStatus,  
2852                               afs_offs_t Pos,                   
2853                               afs_offs_t Length,                
2854                               afs_offs_t FileLength,            
2855                               struct AFSFetchStatus *OutStatus, 
2856                               struct AFSVolSync *Sync)
2857 {
2858     Vnode * targetptr = 0;              /* pointer to input fid */
2859     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
2860     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
2861     int     errorCode = 0;              /* return code for caller */
2862     int     fileCode =  0;              /* return code from vol package */
2863     Volume * volptr = 0;                /* pointer to the volume header */
2864     struct client * client;             /* pointer to client structure */
2865     afs_int32 rights, anyrights;                /* rights for this and any user */
2866     struct client *t_client;            /* tmp ptr to client data */
2867     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
2868     struct rx_connection *tcon;
2869 #if FS_STATS_DETAILED
2870     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2871     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
2872     struct timeval opStartTime,
2873                    opStopTime;              /* Start/stop times for RPC op*/
2874     struct timeval xferStartTime,
2875                    xferStopTime;            /* Start/stop times for xfer portion*/
2876     struct timeval elapsedTime;             /* Transfer time */
2877     afs_size_t bytesToXfer;                         /* # bytes to xfer */
2878     afs_size_t bytesXferred;                        /* # bytes actually xfer */
2879     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
2880
2881     /*
2882      * Set our stats pointers, remember when the RPC operation started, and
2883      * tally the operation.
2884      */
2885     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2886     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2887     FS_LOCK
2888     (opP->numOps)++;
2889     FS_UNLOCK
2890
2891     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
2892             Fid->Volume, Fid->Vnode, Fid->Unique));
2893     TM_GetTimeOfDay(&opStartTime, 0);
2894 #endif /* FS_STATS_DETAILED */
2895
2896     FS_LOCK
2897     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2898     FS_UNLOCK
2899
2900     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
2901         goto Bad_StoreData;
2902
2903     /* Get ptr to client data for user Id for logging */
2904     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2905     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2906     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
2907             Fid->Volume, Fid->Vnode, Fid->Unique,
2908             inet_ntoa(logHostAddr), t_client->ViceId));
2909 #ifdef AFS_LARGEFILE_ENV
2910     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",
2911                 Fid->Volume, Fid->Vnode, Fid->Unique,
2912                 inet_ntoa(logHostAddr), t_client->ViceId,
2913                 (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
2914                 (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff),
2915                 (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff)));
2916 #else /* !AFS_LARGEFILE_ENV */
2917     ViceLog(25, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d, Pos 0X%x, Len 0X%x, FileLen 0X%x\n",
2918                 Fid->Volume, Fid->Vnode, Fid->Unique,
2919                 inet_ntoa(logHostAddr), t_client->ViceId,
2920                 Pos,
2921                 Length,
2922                 FileLength));
2923 #endif /* !AFS_LARGEFILE_ENV */
2924                 
2925
2926     /*
2927      * Get associated volume/vnode for the stored file; caller's rights
2928      * are also returned
2929      */
2930     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
2931                                      MustNOTBeDIR, &parentwhentargetnotdir,
2932                                      &client, WRITE_LOCK, &rights, &anyrights))) {
2933         goto Bad_StoreData;
2934     }
2935
2936     /* set volume synchronization information */
2937     SetVolumeSync(Sync, volptr);
2938
2939     if ((targetptr->disk.type == vSymlink)) {
2940         /* Should we return a better error code here??? */
2941         errorCode = EISDIR;
2942         goto Bad_StoreData;
2943     }
2944
2945     /* Check if we're allowed to store the data */
2946     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
2947                                            CHK_STOREDATA, InStatus))) {
2948         goto Bad_StoreData;
2949     }
2950
2951     /*
2952      * Drop the read lock on the parent directory after saving the parent
2953      * vnode information we need to pass to GetStatus
2954      */
2955     if (parentwhentargetnotdir != NULL) {
2956         tparentwhentargetnotdir = *parentwhentargetnotdir;
2957         VPutVnode(&fileCode, parentwhentargetnotdir);
2958         assert(!fileCode || (fileCode == VSALVAGE));
2959         parentwhentargetnotdir = NULL;
2960     }
2961
2962
2963
2964 #if FS_STATS_DETAILED
2965     /*
2966      * Remember when the data transfer started.
2967      */
2968     TM_GetTimeOfDay(&xferStartTime, 0);
2969 #endif /* FS_STATS_DETAILED */
2970
2971     /* Do the actual storing of the data */
2972 #if FS_STATS_DETAILED
2973     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, acall,
2974                                   (afs_size_t) Pos, (afs_size_t) Length,
2975                                   (afs_size_t) FileLength,
2976                                   (InStatus->Mask & AFS_FSYNC),
2977                                   &bytesToXfer, &bytesXferred);
2978 #else
2979     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
2980                                   acall,
2981                                   (afs_size_t) Pos, (afs_size_t) Length,
2982                                   (afs_size_t) FileLength,
2983                                   (InStatus->Mask & AFS_FSYNC));
2984     if (errorCode && (!targetptr->changed_newTime))
2985             goto Bad_StoreData;
2986 #endif /* FS_STATS_DETAILED */
2987 #if FS_STATS_DETAILED
2988     /*
2989      * At this point, the data transfer is done, for good or ill.  Remember
2990      * when the transfer ended, bump the number of successes/failures, and
2991      * integrate the transfer size and elapsed time into the stats.  If the
2992      * operation failed, we jump to the appropriate point.
2993      */
2994     TM_GetTimeOfDay(&xferStopTime, 0);
2995     FS_LOCK
2996     (xferP->numXfers)++;
2997     if (!errorCode) {
2998         (xferP->numSuccesses)++;
2999
3000         /*
3001          * Bump the xfer sum by the number of bytes actually sent, NOT the
3002          * target number.
3003          */
3004         tot_bytesXferred += bytesXferred;
3005         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3006         tot_bytesXferred &= 0x3FF;
3007         if (bytesXferred < xferP->minBytes)
3008             xferP->minBytes = bytesXferred;
3009         if (bytesXferred > xferP->maxBytes)
3010             xferP->maxBytes = bytesXferred;
3011       
3012         /*
3013          * Tally the size of the object.  Note: we tally the actual size,
3014          * NOT the number of bytes that made it out over the wire.
3015          */
3016         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3017             (xferP->count[0])++;
3018         else
3019             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3020                 (xferP->count[1])++;
3021         else
3022             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3023                 (xferP->count[2])++;
3024         else
3025             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3026                 (xferP->count[3])++;
3027         else
3028             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3029                 (xferP->count[4])++;
3030         else
3031             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3032                 (xferP->count[5])++;
3033         else
3034             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3035                 (xferP->count[6])++;
3036         else
3037             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3038                 (xferP->count[7])++;
3039         else
3040             (xferP->count[8])++;
3041       
3042         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3043         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3044         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3045         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3046             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3047         }
3048         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3049             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3050         }
3051     }
3052     FS_UNLOCK
3053
3054     /*
3055      * Finally, go off to tell our caller the bad news in case the
3056      * store failed.
3057      */
3058     if (errorCode && (!targetptr->changed_newTime))
3059             goto Bad_StoreData;
3060 #endif /* FS_STATS_DETAILED */
3061
3062     /* Update the status of the target's vnode */
3063     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
3064                              volptr, (afs_size_t) 0);
3065
3066     /* Get the updated File's status back to the caller */
3067     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
3068
3069 Bad_StoreData: 
3070     /* Update and store volume/vnode and parent vnodes back */
3071     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3072     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3073
3074     CallPostamble(tcon);
3075
3076 #if FS_STATS_DETAILED
3077     TM_GetTimeOfDay(&opStopTime, 0);
3078     if (errorCode == 0) {
3079         FS_LOCK
3080         (opP->numSuccesses)++;
3081         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3082         fs_stats_AddTo((opP->sumTime), elapsedTime);
3083         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3084         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3085             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3086         }
3087         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3088             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3089         }
3090         FS_UNLOCK
3091       }
3092 #endif /* FS_STATS_DETAILED */
3093
3094     osi_auditU (acall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
3095     return(errorCode);
3096
3097 } /*common_StoreData64*/
3098
3099 afs_int32 SRXAFS_StoreData (struct rx_call *acall,              
3100                             struct AFSFid *Fid,                 
3101                             struct AFSStoreStatus *InStatus,    
3102                             afs_uint32 Pos,                     
3103                             afs_uint32 Length,                  
3104                             afs_uint32 FileLength,              
3105                             struct AFSFetchStatus *OutStatus,   
3106                             struct AFSVolSync *Sync)
3107 {
3108     int code;
3109
3110     code = common_StoreData64 (acall, Fid, InStatus, Pos, Length, FileLength,
3111                              OutStatus, Sync);
3112     return code;
3113
3114 } /*SRXAFS_StoreData*/
3115
3116 afs_int32 SRXAFS_StoreData64 (struct rx_call *acall,            
3117                               struct AFSFid *Fid,               
3118                               struct AFSStoreStatus *InStatus,  
3119                               afs_uint64 Pos,                   
3120                               afs_uint64 Length,                
3121                               afs_uint64 FileLength,            
3122                               struct AFSFetchStatus *OutStatus, 
3123                               struct AFSVolSync *Sync)
3124 {
3125     int code;
3126     afs_offs_t tPos;
3127     afs_offs_t tLength;
3128     afs_offs_t tFileLength;
3129
3130 #ifdef AFS_64BIT_ENV
3131 #ifndef AFS_LARGEFILE_ENV
3132     if (FileLength > 0x7fffffff)
3133         return E2BIG;
3134 #endif /* !AFS_LARGEFILE_ENV */
3135     tPos = Pos;
3136     tLength = Length;
3137     tFileLength = FileLength;
3138 #else /* AFS_64BIT_ENV */
3139     if (FileLength.high)
3140         return E2BIG;
3141     tPos = Pos.low;
3142     tLength = Length.low;
3143     tFileLength = FileLength.low;
3144 #endif /* AFS_64BIT_ENV */
3145
3146     code = common_StoreData64 (acall, Fid, InStatus, tPos, tLength, tFileLength,
3147                              OutStatus, Sync);
3148     return code;
3149 }
3150
3151 afs_int32 SRXAFS_StoreACL (struct rx_call *acall,               
3152                            struct AFSFid *Fid,                  
3153                            struct AFSOpaque *AccessList,        
3154                            struct AFSFetchStatus *OutStatus,
3155                            struct AFSVolSync *Sync)
3156 {
3157     Vnode * targetptr = 0;              /* pointer to input fid */
3158     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3159     int     errorCode = 0;              /* return code for caller */
3160     struct AFSStoreStatus InStatus;     /* Input status for fid */
3161     Volume * volptr = 0;                /* pointer to the volume header */
3162     struct client * client;             /* pointer to client structure */
3163     afs_int32 rights, anyrights;                /* rights for this and any user */
3164     struct rx_connection *tcon;
3165     struct client *t_client;            /* tmp ptr to client data */
3166     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
3167 #if FS_STATS_DETAILED
3168     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3169     struct timeval opStartTime,
3170                    opStopTime;              /* Start/stop times for RPC op*/
3171     struct timeval elapsedTime;             /* Transfer time */
3172
3173     /*
3174      * Set our stats pointer, remember when the RPC operation started, and
3175      * tally the operation.
3176      */
3177     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3178     FS_LOCK
3179     (opP->numOps)++;
3180     FS_UNLOCK
3181     TM_GetTimeOfDay(&opStartTime, 0);
3182 #endif /* FS_STATS_DETAILED */
3183     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
3184         goto Bad_StoreACL;
3185
3186     /* Get ptr to client data for user Id for logging */
3187     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3188     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3189     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
3190             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3191             inet_ntoa(logHostAddr), t_client->ViceId));
3192     FS_LOCK
3193     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3194     FS_UNLOCK
3195
3196     InStatus.Mask = 0;      /* not storing any status */
3197
3198     /*
3199      * Get associated volume/vnode for the target dir; caller's rights
3200      * are also returned.
3201      */
3202     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3203                                      MustBeDIR, &parentwhentargetnotdir,
3204                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3205         goto Bad_StoreACL;
3206     }
3207
3208     /* set volume synchronization information */
3209     SetVolumeSync(Sync, volptr);
3210
3211     /* Check if we have permission to change the dir's ACL */
3212     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3213                                            CHK_STOREACL, &InStatus))) {
3214         goto Bad_StoreACL;
3215     }
3216
3217     /* Build and store the new Access List for the dir */
3218     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3219         goto Bad_StoreACL;
3220     }
3221     
3222     targetptr->changed_newTime = 1; /* status change of directory */
3223
3224     /* convert the write lock to a read lock before breaking callbacks */
3225     VVnodeWriteToRead(&errorCode, targetptr);
3226     assert(!errorCode || errorCode == VSALVAGE);
3227
3228     /* break call backs on the directory  */
3229     BreakCallBack(client->host, Fid, 0);
3230
3231     /* Get the updated dir's status back to the caller */
3232     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3233
3234 Bad_StoreACL: 
3235     /* Update and store volume/vnode and parent vnodes back */
3236     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3237     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
3238     CallPostamble(tcon);
3239
3240 #if FS_STATS_DETAILED
3241     TM_GetTimeOfDay(&opStopTime, 0);
3242     if (errorCode == 0) {
3243       FS_LOCK
3244       (opP->numSuccesses)++;
3245       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3246       fs_stats_AddTo((opP->sumTime), elapsedTime);
3247       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3248       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3249         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3250       }
3251       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3252         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3253       }
3254       FS_UNLOCK
3255     }
3256 #endif /* FS_STATS_DETAILED */
3257
3258     osi_auditU (acall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
3259     return errorCode;
3260
3261 } /*SRXAFS_StoreACL*/
3262
3263
3264 /*
3265  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3266  * should be merged when possible.
3267  */
3268 static afs_int32
3269 SAFSS_StoreStatus (struct rx_call *acall,               
3270                    struct AFSFid *Fid,                  
3271                    struct AFSStoreStatus *InStatus,     
3272                    struct AFSFetchStatus *OutStatus,    
3273                    struct AFSVolSync *Sync)
3274
3275 {
3276     Vnode * targetptr = 0;              /* pointer to input fid */
3277     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
3278     int     errorCode = 0;              /* return code for caller */
3279     Volume * volptr = 0;                /* pointer to the volume header */
3280     struct client * client;             /* pointer to client structure */
3281     afs_int32 rights, anyrights;                /* rights for this and any user */
3282     struct client *t_client;            /* tmp ptr to client data */
3283     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3284     struct rx_connection *tcon = rx_ConnectionOf(acall);
3285
3286     /* Get ptr to client data for user Id for logging */
3287     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3288     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3289     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
3290             Fid->Volume, Fid->Vnode,    Fid->Unique,
3291             inet_ntoa(logHostAddr), t_client->ViceId));
3292     FS_LOCK
3293     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3294     FS_UNLOCK
3295     /*
3296      * Get volume/vnode for the target file; caller's rights to it are
3297      * also returned
3298      */
3299     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3300                                      DONTCHECK, &parentwhentargetnotdir,
3301                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3302         goto Bad_StoreStatus;
3303     }
3304
3305     /* set volume synchronization information */
3306     SetVolumeSync(Sync, volptr);
3307
3308     /* Check if the caller has proper permissions to store status to Fid */
3309     if ((errorCode = Check_PermissionRights(targetptr, client, rights,
3310                                            CHK_STORESTATUS, InStatus))) {
3311         goto Bad_StoreStatus;
3312     }
3313     /*
3314      * Check for a symbolic link; we can't chmod these (otherwise could
3315      * change a symlink to a mt pt or vice versa)
3316      */
3317     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3318         errorCode = EINVAL;
3319         goto Bad_StoreStatus;
3320     }
3321
3322     /* Update the status of the target's vnode */
3323     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3324                              (parentwhentargetnotdir ?
3325                               parentwhentargetnotdir : targetptr), volptr,
3326                              (afs_size_t)0);
3327
3328     /* convert the write lock to a read lock before breaking callbacks */
3329     VVnodeWriteToRead(&errorCode, targetptr);
3330     assert(!errorCode || errorCode == VSALVAGE);
3331
3332     /* Break call backs on Fid */
3333     BreakCallBack(client->host, Fid, 0);
3334
3335     /* Return the updated status back to caller */
3336     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
3337
3338 Bad_StoreStatus: 
3339     /* Update and store volume/vnode and parent vnodes back */
3340     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3341     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3342     return errorCode;
3343
3344 } /*SAFSS_StoreStatus*/
3345
3346
3347 afs_int32 SRXAFS_StoreStatus (struct rx_call *acall,            
3348                               struct AFSFid *Fid,               
3349                               struct AFSStoreStatus *InStatus,  
3350                               struct AFSFetchStatus *OutStatus, 
3351                               struct AFSVolSync *Sync)
3352 {
3353     afs_int32 code;
3354     struct rx_connection *tcon;
3355 #if FS_STATS_DETAILED
3356     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3357     struct timeval opStartTime,
3358                    opStopTime;              /* Start/stop times for RPC op*/
3359     struct timeval elapsedTime;             /* Transfer time */
3360
3361     /*
3362      * Set our stats pointer, remember when the RPC operation started, and
3363      * tally the operation.
3364      */
3365     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3366     FS_LOCK
3367     (opP->numOps)++;
3368     FS_UNLOCK
3369     TM_GetTimeOfDay(&opStartTime, 0);
3370 #endif /* FS_STATS_DETAILED */
3371
3372     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3373         goto Bad_StoreStatus;
3374
3375     code = SAFSS_StoreStatus (acall, Fid, InStatus, OutStatus, Sync);
3376
3377 Bad_StoreStatus:
3378     CallPostamble(tcon);
3379
3380 #if FS_STATS_DETAILED
3381     TM_GetTimeOfDay(&opStopTime, 0);
3382     if (code == 0) {
3383       FS_LOCK
3384       (opP->numSuccesses)++;
3385       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3386       fs_stats_AddTo((opP->sumTime), elapsedTime);
3387       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3388       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3389         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3390       }
3391       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3392         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3393       }
3394       FS_UNLOCK
3395     }
3396
3397 #endif /* FS_STATS_DETAILED */
3398
3399     osi_auditU (acall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
3400     return code;
3401
3402 } /*SRXAFS_StoreStatus*/
3403
3404
3405 /*
3406  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3407  * merged in when possible.
3408  */
3409 static afs_int32
3410 SAFSS_RemoveFile (struct rx_call *acall,               
3411                   struct AFSFid *DirFid,               
3412                   char *Name,                          
3413                   struct AFSFetchStatus *OutDirStatus, 
3414                   struct AFSVolSync *Sync)
3415 {
3416     Vnode * parentptr = 0;              /* vnode of input Directory */
3417     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3418     Vnode * targetptr = 0;              /* file to be deleted */
3419     Volume * volptr = 0;                /* pointer to the volume header */
3420     AFSFid fileFid;                     /* area for Fid from the directory */
3421     int     errorCode = 0;              /* error code */
3422     DirHandle dir;                      /* Handle for dir package I/O */
3423     struct client * client;             /* pointer to client structure */
3424     afs_int32 rights, anyrights;                /* rights for this and any user */
3425     struct client *t_client;            /* tmp ptr to client data */
3426     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3427     struct rx_connection *tcon = rx_ConnectionOf(acall);
3428
3429     FidZero(&dir);
3430     /* Get ptr to client data for user Id for logging */
3431     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3432     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3433     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3434             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3435             inet_ntoa(logHostAddr), t_client->ViceId));
3436     FS_LOCK
3437     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3438     FS_UNLOCK
3439     /*
3440      * Get volume/vnode for the parent dir; caller's access rights are
3441      * also returned
3442      */
3443     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3444                                      MustBeDIR, &parentwhentargetnotdir,
3445                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3446         goto Bad_RemoveFile;
3447     }
3448     /* set volume synchronization information */
3449     SetVolumeSync(Sync, volptr);
3450
3451     /* Does the caller has delete (& write) access to the parent directory? */
3452     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3453         goto Bad_RemoveFile;
3454     }
3455
3456     /* Actually delete the desired file */
3457     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
3458                                  &fileFid, Name, MustNOTBeDIR))) {
3459         goto Bad_RemoveFile;
3460     }
3461
3462     /* Update the vnode status of the parent dir */
3463 #if FS_STATS_DETAILED
3464     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3465                              parentptr->disk.linkCount, client->InSameNetwork);
3466 #else
3467     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3468                              parentptr->disk.linkCount);
3469 #endif /* FS_STATS_DETAILED */
3470
3471     /* Return the updated parent dir's status back to caller */
3472     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3473
3474     /* Handle internal callback state for the parent and the deleted file */
3475     if (targetptr->disk.linkCount == 0) {
3476         /* no references left, discard entry */
3477         DeleteFileCallBacks(&fileFid);
3478         /* convert the parent lock to a read lock before breaking callbacks */
3479         VVnodeWriteToRead(&errorCode, parentptr);
3480         assert(!errorCode || errorCode == VSALVAGE);
3481     } else {
3482         /* convert the parent lock to a read lock before breaking callbacks */
3483         VVnodeWriteToRead(&errorCode, parentptr);
3484         assert(!errorCode || errorCode == VSALVAGE);
3485         /* convert the target lock to a read lock before breaking callbacks */
3486         VVnodeWriteToRead(&errorCode, targetptr);
3487         assert(!errorCode || errorCode == VSALVAGE);
3488         /* tell all the file has changed */
3489         BreakCallBack(client->host, &fileFid, 1);
3490     }
3491
3492     /* break call back on the directory */
3493     BreakCallBack(client->host, DirFid, 0);
3494
3495 Bad_RemoveFile: 
3496     /* Update and store volume/vnode and parent vnodes back */
3497     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3498     FidZap(&dir);
3499     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
3500     return errorCode;
3501
3502 } /*SAFSS_RemoveFile*/
3503
3504
3505 afs_int32 SRXAFS_RemoveFile (struct rx_call *acall,
3506                              struct AFSFid *DirFid,
3507                              char *Name,
3508                              struct AFSFetchStatus *OutDirStatus,
3509                              struct AFSVolSync *Sync)
3510 {
3511     afs_int32 code;
3512     struct rx_connection *tcon;
3513 #if FS_STATS_DETAILED
3514     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3515     struct timeval opStartTime,
3516                    opStopTime;              /* Start/stop times for RPC op*/
3517     struct timeval elapsedTime;             /* Transfer time */
3518
3519     /*
3520      * Set our stats pointer, remember when the RPC operation started, and
3521      * tally the operation.
3522      */
3523     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3524     FS_LOCK
3525     (opP->numOps)++;
3526     FS_UNLOCK
3527     TM_GetTimeOfDay(&opStartTime, 0);
3528 #endif /* FS_STATS_DETAILED */
3529
3530     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3531         goto Bad_RemoveFile;
3532
3533     code = SAFSS_RemoveFile (acall, DirFid, Name, OutDirStatus, Sync);
3534
3535 Bad_RemoveFile:    
3536     CallPostamble(tcon);
3537
3538 #if FS_STATS_DETAILED
3539     TM_GetTimeOfDay(&opStopTime, 0);
3540     if (code == 0) {
3541       FS_LOCK
3542       (opP->numSuccesses)++;
3543       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3544       fs_stats_AddTo((opP->sumTime), elapsedTime);
3545       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3546       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3547         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3548       }
3549       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3550         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3551       }
3552       FS_UNLOCK
3553     }
3554
3555 #endif /* FS_STATS_DETAILED */
3556
3557     osi_auditU (acall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3558     return code;
3559
3560 } /*SRXAFS_RemoveFile*/
3561
3562
3563 /*
3564  * This routine is called exclusively from SRXAFS_CreateFile(), and should
3565  * be merged in when possible.
3566  */
3567 static afs_int32
3568 SAFSS_CreateFile (struct rx_call *acall,
3569                   struct AFSFid *DirFid,
3570                   char *Name,
3571                   struct AFSStoreStatus *InStatus,
3572                   struct AFSFid *OutFid,
3573                   struct AFSFetchStatus *OutFidStatus,
3574                   struct AFSFetchStatus *OutDirStatus,
3575                   struct AFSCallBack *CallBack,
3576                   struct AFSVolSync *Sync)
3577 {
3578     Vnode * parentptr = 0;              /* vnode of input Directory */
3579     Vnode * targetptr = 0;              /* vnode of the new file */
3580     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3581     Volume * volptr = 0;                /* pointer to the volume header */
3582     int     errorCode = 0;              /* error code */
3583     DirHandle dir;                      /* Handle for dir package I/O */
3584     struct client * client;             /* pointer to client structure */
3585     afs_int32 rights, anyrights;        /* rights for this and any user */
3586     struct client *t_client;            /* tmp ptr to client data */
3587     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3588     struct rx_connection *tcon = rx_ConnectionOf(acall);
3589
3590     FidZero(&dir);
3591
3592     /* Get ptr to client data for user Id for logging */
3593     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3594     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3595     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3596             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3597             inet_ntoa(logHostAddr), t_client->ViceId));
3598     FS_LOCK
3599     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3600     FS_UNLOCK
3601     if (!FileNameOK(Name)) {
3602       errorCode = EINVAL;
3603       goto Bad_CreateFile;
3604     }
3605
3606     /*
3607      * Get associated volume/vnode for the parent dir; caller long are
3608      * also returned
3609      */
3610     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3611                                      MustBeDIR, &parentwhentargetnotdir,
3612                                      &client, WRITE_LOCK, &rights, &anyrights))) {
3613         goto Bad_CreateFile;
3614     }
3615
3616     /* set volume synchronization information */
3617     SetVolumeSync(Sync, volptr);
3618
3619     /* Can we write (and insert) onto the parent directory? */
3620     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3621         goto Bad_CreateFile;
3622     }
3623     /* get a new vnode for the file to be created and set it up */
3624     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
3625                                    Name, OutFid, vFile, nBlocks(0)))) {
3626         goto Bad_CreateFile;
3627     }
3628
3629     /* update the status of the parent vnode */
3630 #if FS_STATS_DETAILED
3631     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3632                              parentptr->disk.linkCount, client->InSameNetwork);
3633 #else
3634     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3635                              parentptr->disk.linkCount);
3636 #endif /* FS_STATS_DETAILED */
3637
3638     /* update the status of the new file's vnode */
3639     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3640                              parentptr, volptr, (afs_size_t)0);
3641
3642     /* set up the return status for the parent dir and the newly created file */
3643     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3644     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3645
3646     /* convert the write lock to a read lock before breaking callbacks */
3647     VVnodeWriteToRead(&errorCode, parentptr);
3648     assert(!errorCode || errorCode == VSALVAGE);
3649     
3650     /* break call back on parent dir */
3651     BreakCallBack(client->host, DirFid, 0);
3652
3653     /* Return a callback promise for the newly created file to the caller */
3654     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3655
3656 Bad_CreateFile:
3657     /* Update and store volume/vnode and parent vnodes back */
3658     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3659     FidZap(&dir);
3660     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
3661     return errorCode;
3662
3663 } /*SAFSS_CreateFile*/
3664
3665
3666 afs_int32 SRXAFS_CreateFile (struct rx_call *acall,
3667                              struct AFSFid *DirFid,
3668                              char *Name,
3669                              struct AFSStoreStatus *InStatus,
3670                              struct AFSFid *OutFid,
3671                              struct AFSFetchStatus *OutFidStatus,
3672                              struct AFSFetchStatus *OutDirStatus, 
3673                              struct AFSCallBack *CallBack,       
3674                              struct AFSVolSync *Sync)
3675 {
3676     afs_int32 code;
3677     struct rx_connection *tcon;
3678 #if FS_STATS_DETAILED
3679     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3680     struct timeval opStartTime,
3681                    opStopTime;              /* Start/stop times for RPC op*/
3682     struct timeval elapsedTime;             /* Transfer time */
3683
3684     /*
3685      * Set our stats pointer, remember when the RPC operation started, and
3686      * tally the operation.
3687      */
3688     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3689     FS_LOCK
3690     (opP->numOps)++;
3691     FS_UNLOCK
3692     TM_GetTimeOfDay(&opStartTime, 0);
3693 #endif /* FS_STATS_DETAILED */
3694
3695     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
3696         goto Bad_CreateFile;
3697
3698     code = SAFSS_CreateFile (acall, DirFid, Name, InStatus, OutFid,
3699                             OutFidStatus, OutDirStatus, CallBack, Sync);
3700
3701 Bad_CreateFile:    
3702     CallPostamble(tcon);
3703
3704 #if FS_STATS_DETAILED
3705     TM_GetTimeOfDay(&opStopTime, 0);
3706     if (code == 0) {
3707       FS_LOCK
3708       (opP->numSuccesses)++;
3709       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3710       fs_stats_AddTo((opP->sumTime), elapsedTime);
3711       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3712       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3713         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3714       }
3715       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3716         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3717       }
3718       FS_UNLOCK
3719     }
3720 #endif /* FS_STATS_DETAILED */
3721
3722     osi_auditU (acall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3723     return code;
3724
3725 } /*SRXAFS_CreateFile*/
3726
3727
3728 /*
3729  * This routine is called exclusively from SRXAFS_Rename(), and should be
3730  * merged in when possible.
3731  */
3732 static afs_int32
3733 SAFSS_Rename (struct rx_call *acall,
3734               struct AFSFid *OldDirFid,
3735               char *OldName,
3736               struct AFSFid *NewDirFid,
3737               char *NewName,
3738               struct AFSFetchStatus *OutOldDirStatus,
3739               struct AFSFetchStatus *OutNewDirStatus,
3740               struct AFSVolSync *Sync)
3741 {
3742     Vnode * oldvptr = 0;        /* vnode of the old Directory */
3743     Vnode * newvptr = 0;        /* vnode of the new Directory */
3744     Vnode * fileptr = 0;        /* vnode of the file to move */
3745     Vnode * newfileptr = 0;     /* vnode of the file to delete */
3746     Vnode * testvptr = 0;       /* used in directory tree walk */
3747     Vnode * parent = 0;         /* parent for use in SetAccessList */
3748     int     errorCode = 0;      /* error code */
3749     int     fileCode = 0;       /* used when writing Vnodes */
3750     VnodeId testnode;           /* used in directory tree walk */
3751     AFSFid fileFid;             /* Fid of file to move */
3752     AFSFid newFileFid;          /* Fid of new file */
3753     DirHandle olddir;           /* Handle for dir package I/O */
3754     DirHandle newdir;           /* Handle for dir package I/O */
3755     DirHandle filedir;          /* Handle for dir package I/O */
3756     DirHandle newfiledir;       /* Handle for dir package I/O */
3757     Volume * volptr = 0;        /* pointer to the volume header */
3758     struct client * client;     /* pointer to client structure */
3759     afs_int32 rights, anyrights;        /* rights for this and any user */
3760     afs_int32 newrights;                /* rights for this user */
3761     afs_int32 newanyrights;             /* rights for any user */
3762     int doDelete;               /* deleted the rename target (ref count now 0) */
3763     int code;
3764     struct client *t_client;            /* tmp ptr to client data */
3765     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3766     struct rx_connection *tcon = rx_ConnectionOf(acall);
3767
3768     FidZero(&olddir);
3769     FidZero(&newdir);
3770     FidZero(&filedir);
3771     FidZero(&newfiledir);
3772
3773     /* Get ptr to client data for user Id for logging */
3774     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3775     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3776     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
3777             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3778             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3779             NewDirFid->Unique,
3780             inet_ntoa(logHostAddr), t_client->ViceId));
3781     FS_LOCK
3782     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3783     FS_UNLOCK
3784     if (!FileNameOK(NewName)) {
3785         errorCode = EINVAL;
3786         goto Bad_Rename;
3787     }
3788     if (OldDirFid->Volume != NewDirFid->Volume) {
3789         DFlush();
3790         errorCode = EXDEV;
3791         goto Bad_Rename;
3792     }
3793     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
3794          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
3795          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
3796         DFlush();
3797         errorCode = EINVAL;
3798         goto Bad_Rename;
3799     }
3800
3801     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3802         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
3803                                           &oldvptr, MustBeDIR, &parent,
3804                                           &client, WRITE_LOCK, &rights,
3805                                           &anyrights)) {
3806             DFlush();
3807             goto Bad_Rename;
3808         }
3809         if (OldDirFid->Vnode == NewDirFid->Vnode) {
3810             newvptr = oldvptr;
3811             newrights = rights, newanyrights = anyrights;
3812         }
3813         else
3814             if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3815                                              &newvptr, MustBeDIR, &parent,
3816                                              &client, WRITE_LOCK, &newrights,
3817                                              &newanyrights))) {
3818                 DFlush();
3819                 goto Bad_Rename;
3820             }
3821     }
3822     else {
3823         if ((errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
3824                                          &newvptr, MustBeDIR, &parent,
3825                                          &client, WRITE_LOCK, &newrights,
3826                                          &newanyrights))) {
3827             DFlush();
3828             goto Bad_Rename;
3829         }
3830         if ((errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
3831                                          MustBeDIR, &parent, &client, WRITE_LOCK,
3832                                          &rights, &anyrights))) {
3833             DFlush();
3834             goto Bad_Rename;
3835         }
3836     }
3837
3838     /* set volume synchronization information */
3839     SetVolumeSync(Sync, volptr);
3840
3841     if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3842         goto Bad_Rename;
3843     }
3844     if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3845         goto Bad_Rename;
3846     }
3847
3848     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3849     *  call to CopyOnWrite returns error, it is not necessary to revert back
3850     *  the effects of the first call because the contents of the volume is 
3851     *  not modified, it is only replicated.
3852     */
3853     if (oldvptr->disk.cloned)
3854     {
3855         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
3856          if ( ( errorCode = CopyOnWrite(oldvptr, volptr) ) )
3857                 goto Bad_Rename;
3858     }
3859     SetDirHandle(&olddir, oldvptr);
3860     if (newvptr->disk.cloned)
3861     {
3862         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
3863         if ( ( errorCode = CopyOnWrite(newvptr, volptr) ) )
3864                 goto Bad_Rename;        
3865     }
3866
3867     SetDirHandle(&newdir, newvptr);
3868
3869     /* Lookup the file to delete its vnode */
3870     if (Lookup(&olddir, OldName, &fileFid)) {
3871         errorCode = ENOENT;
3872         goto Bad_Rename;
3873     }
3874     if (fileFid.Vnode == oldvptr->vnodeNumber ||
3875         fileFid.Vnode == newvptr->vnodeNumber) {
3876         errorCode = FSERR_ELOOP;
3877         goto Bad_Rename;
3878     }
3879     fileFid.Volume = V_id(volptr);
3880     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3881     if (errorCode != 0) {
3882         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
3883         VTakeOffline (volptr);
3884         goto Bad_Rename;
3885     }
3886     if (fileptr->disk.uniquifier != fileFid.Unique) {
3887         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
3888         VTakeOffline (volptr);
3889         errorCode = EIO;
3890         goto Bad_Rename;
3891     }
3892
3893     if (fileptr->disk.type != vDirectory &&
3894         oldvptr != newvptr &&
3895         fileptr->disk.linkCount != 1) {
3896         /*
3897          * Hard links exist to this file - cannot move one of the links to
3898          * a new directory because of AFS restrictions (this is the same
3899          * reason that links cannot be made across directories, i.e.
3900          * access lists)
3901          */
3902         errorCode = EXDEV;
3903         goto Bad_Rename;
3904     }
3905
3906     /* Lookup the new file  */
3907     if (!(Lookup(&newdir, NewName, &newFileFid))) {
3908         if (readonlyServer) {
3909             errorCode = VREADONLY;
3910             goto Bad_Rename;
3911         }
3912         if (!(newrights & PRSFS_DELETE)) {
3913             errorCode = EACCES;
3914             goto Bad_Rename;
3915         }
3916         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
3917                 newFileFid.Vnode == newvptr->vnodeNumber ||
3918                 newFileFid.Vnode == fileFid.Vnode) {
3919             errorCode = EINVAL;
3920             goto Bad_Rename;
3921         }
3922         newFileFid.Volume = V_id(volptr);
3923         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3924         if (errorCode != 0) {
3925             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
3926             VTakeOffline (volptr);
3927             goto Bad_Rename;
3928         }
3929         if (fileptr->disk.uniquifier != fileFid.Unique) {
3930             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
3931             VTakeOffline (volptr);
3932             errorCode = EIO;
3933             goto Bad_Rename;
3934         }
3935         SetDirHandle(&newfiledir, newfileptr);
3936         /* Now check that we're moving directories over directories properly, etc.
3937          * return proper POSIX error codes:
3938          * if fileptr is a file and new is a dir: EISDIR.
3939          * if fileptr is a dir and new is a file: ENOTDIR.
3940          * Also, dir to be removed must be empty, of course.
3941          */
3942         if (newfileptr->disk.type == vDirectory) {
3943             if (fileptr->disk.type != vDirectory) {
3944                 errorCode = EISDIR;
3945                 goto Bad_Rename;
3946             }
3947             if ((IsEmpty(&newfiledir))) {
3948                 errorCode = EEXIST;
3949                 goto Bad_Rename;
3950             }
3951         }
3952         else {
3953             if (fileptr->disk.type == vDirectory) {
3954                 errorCode = ENOTDIR;
3955                 goto Bad_Rename;
3956             }
3957         }
3958     }
3959
3960     /*
3961      * ok - now we check that the old name is not above new name in the
3962      * directory structure.  This is to prevent removing a subtree alltogether
3963      */
3964     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3965         for (testnode = newvptr->disk.parent; testnode != 0;) {
3966             if (testnode == oldvptr->vnodeNumber) {
3967                 testnode = oldvptr->disk.parent;
3968                 continue;
3969             }
3970             if ((testnode == fileptr->vnodeNumber) ||
3971                 (testnode == newvptr->vnodeNumber)) {
3972                 errorCode = FSERR_ELOOP;
3973                 goto Bad_Rename;
3974             }
3975             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3976                 errorCode = FSERR_ELOOP;
3977                 goto Bad_Rename;
3978             }
3979             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3980             assert(errorCode == 0);
3981             testnode = testvptr->disk.parent;
3982             VPutVnode(&errorCode, testvptr);
3983             assert(errorCode == 0);
3984         }
3985     }
3986     /* Do the CopyonWrite first before modifying anything else. Copying is
3987      *  required because we may have to change entries for .. 
3988      */
3989     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
3990     {
3991         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
3992         if ( ( errorCode = CopyOnWrite(fileptr, volptr) ) )
3993                 goto Bad_Rename;
3994     }
3995
3996     /* If the new name exists already, delete it and the file it points to */
3997     doDelete = 0;
3998     if (newfileptr) {
3999         /* Delete NewName from its directory */
4000         code = Delete(&newdir, NewName);
4001         assert(code == 0);
4002
4003         /* Drop the link count */
4004         newfileptr->disk.linkCount--;
4005         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
4006             afs_size_t  newSize;
4007             VN_GET_LEN(newSize, newfileptr);
4008             VAdjustDiskUsage(&errorCode, volptr,
4009                              -nBlocks(newSize), (afs_size_t) 0);
4010             if (VN_GET_INO(newfileptr)) {
4011                 IH_REALLYCLOSE(newfileptr->handle);
4012                 errorCode = IH_DEC(V_linkHandle(volptr),
4013                                  VN_GET_INO(newfileptr),
4014                                  V_parentId(volptr));
4015                 IH_RELEASE(newfileptr->handle);
4016                 if (errorCode == -1) {
4017                     ViceLog(0, ("Del: inode=%s, name=%s, errno=%d\n",
4018                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
4019                                 NewName, errno));
4020                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
4021                         ViceLog(0, ("Do we need to fsck?"));
4022                 } 
4023             }
4024             VN_SET_INO(newfileptr, (Inode)0);
4025             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
4026             doDelete = 1;
4027         } else {
4028             /* Link count did not drop to zero.
4029              * Mark NewName vnode as changed - updates stime.
4030              */
4031             newfileptr->changed_newTime = 1;
4032         }
4033     }
4034     
4035     /*
4036      * If the create below fails, and the delete above worked, we have
4037      * removed the new name and not replaced it.  This is not very likely,