afs-error-translation-update-20030306
[openafs.git] / src / viced / afsfileprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*  afs_fileprocs.c - Complete File Server request routines              */
11 /*                                                                       */
12 /*  Information Technology Center                                        */
13 /*  Carnegie Mellon University                                           */
14 /*                                                                       */
15 /*  Date: 8/10/88                                                        */
16 /*                                                                       */
17 /*  Function    - A set of routines to handle the various file Server    */
18 /*                  requests; these routines are invoked by rxgen.       */
19 /*                                                                       */
20 /* ********************************************************************** */
21
22 /* 
23  * in Check_PermissionRights, certain privileges are afforded to the owner 
24  * of the volume, or the owner of a file.  Are these considered "use of 
25  * privilege"? 
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30
31 RCSID("$Header$");
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #ifdef  AFS_SGI_ENV
37 #undef SHARED           /* XXX */
38 #endif
39 #ifdef AFS_NT40_ENV
40 #include <fcntl.h>
41 #else
42 #include <sys/param.h>
43 #include <sys/file.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48
49 #ifdef HAVE_STRING_H
50 #include <string.h>
51 #else
52 #ifdef HAVE_STRINGS_H
53 #include <strings.h>
54 #endif
55 #endif
56
57 #ifndef AFS_LINUX20_ENV
58 #include <net/if.h>
59 #include <netinet/if_ether.h>
60 #endif
61 #endif
62 #ifdef AFS_HPUX_ENV
63 /* included early because of name conflict on IOPEN */
64 #include <sys/inode.h>
65 #ifdef IOPEN
66 #undef IOPEN
67 #endif
68 #endif /* AFS_HPUX_ENV */
69 #include <afs/stds.h>
70 #include <rx/xdr.h>
71 #include <afs/nfs.h>
72 #include <afs/assert.h>
73 #include <lwp.h>
74 #include <lock.h>
75 #include <afs/afsint.h>
76 #include <afs/vldbint.h>
77 #include <afs/errors.h>
78 #include <afs/ihandle.h>
79 #include <afs/vnode.h>
80 #include <afs/volume.h>
81 #include <afs/acl.h>
82 #include <afs/ptclient.h>
83 #include <afs/prs_fs.h>
84 #include <rx/rx.h>
85 #include <rx/rx_globals.h>
86 #include <sys/stat.h>
87 #if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
88 #include <sys/map.h>
89 #endif
90 #if !defined(AFS_NT40_ENV)
91 #include <unistd.h>
92 #endif
93 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
94 #ifdef  AFS_AIX_ENV
95 #include <sys/statfs.h>
96 #include <sys/lockf.h>
97 #else
98 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
99 #include <sys/dk.h>
100 #endif
101 #endif
102 #endif
103 #include <afs/cellconfig.h>
104 #include <afs/keys.h>
105
106 #include <afs/auth.h>
107 #include <signal.h>
108 #include <afs/partition.h>
109 #include "viced_prototypes.h"
110 #include "viced.h"
111 #include "host.h"
112 #include <afs/unified_afs.h>
113 #include <afs/audit.h>
114 #include <afs/afsutil.h>
115
116 #ifdef AFS_PTHREAD_ENV
117 pthread_mutex_t fileproc_glock_mutex;
118 #endif /* AFS_PTHREAD_ENV */
119
120
121 /* Useful local defines used by this module */
122
123 #define DONTCHECK       0
124 #define MustNOTBeDIR    1
125 #define MustBeDIR       2
126
127 #define TVS_SDATA       1
128 #define TVS_SSTATUS     2
129 #define TVS_CFILE       4
130 #define TVS_SLINK       8
131 #define TVS_MKDIR       0x10
132
133 #define CHK_FETCH       0x10
134 #define CHK_FETCHDATA   0x10
135 #define CHK_FETCHACL    0x11
136 #define CHK_FETCHSTATUS 0x12
137 #define CHK_STOREDATA   0x00
138 #define CHK_STOREACL    0x01
139 #define CHK_STORESTATUS 0x02
140
141 #define OWNERREAD       0400
142 #define OWNERWRITE      0200
143 #define OWNEREXEC       0100
144 #ifdef USE_GROUP_PERMS
145 #define GROUPREAD       0040
146 #define GROUPWRITE      0020
147 #define GROUPREXEC      0010
148 #endif
149
150 /* The following errors were not defined in NT. They are given unique
151  * names here to avoid any potential collision.
152  */
153 #define FSERR_ELOOP              90
154 #define FSERR_EOPNOTSUPP        122
155 #define FSERR_ECONNREFUSED      130
156
157 #define NOTACTIVECALL   0
158 #define ACTIVECALL      1
159
160 #define CREATE_SGUID_ADMIN_ONLY 1
161
162 extern struct afsconf_dir *confDir;
163 extern afs_int32 dataVersionHigh;
164
165 extern  int         SystemId;
166 static struct AFSCallStatistics AFSCallStats;
167 #if FS_STATS_DETAILED
168 struct fs_stats_FullPerfStats afs_FullPerfStats;
169 extern int AnonymousID;
170 #endif /* FS_STATS_DETAILED */
171 #if TRANSARC_VOL_STATS
172 static const char nullString[] = "";
173 #endif /* TRANSARC_VOL_STATS */
174
175 struct afs_FSStats {
176     afs_int32 NothingYet;
177 };
178
179 struct afs_FSStats afs_fsstats;
180
181 void    ResetDebug(), SetDebug(), Terminate();
182
183 int     LogLevel = 0;
184 int     supported = 1;
185 int     Console = 0;
186 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
187 afs_int32 PctSpare;
188 extern afs_int32 implicitAdminRights;
189 extern afs_int32 readonlyServer;
190
191 /*
192  * Externals used by the xstat code.
193  */
194 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
195 extern int CEs, CEBlocks;
196
197 extern int HTs, HTBlocks;
198
199 afs_int32
200 FetchData_RXStyle(Volume *volptr, 
201                   Vnode *targetptr, 
202                   register struct rx_call *Call,
203                   afs_size_t Pos,
204                   afs_size_t Len,
205                   afs_int32 Int64Mode,
206 #if FS_STATS_DETAILED
207                   afs_size_t *a_bytesToFetchP,
208                   afs_size_t *a_bytesFetchedP
209 #endif /* FS_STATS_DETAILED */
210                   );
211
212 afs_int32
213 StoreData_RXStyle(Volume *volptr,
214                   Vnode *targetptr,
215                   struct AFSFid *Fid,
216                   struct client *client,
217                   register struct rx_call *Call,
218                   afs_offs_t Pos,
219                   afs_offs_t Length,
220                   afs_offs_t FileLength,
221                   int sync,
222 #if FS_STATS_DETAILED
223                   afs_size_t *a_bytesToStoreP,
224                   afs_size_t *a_bytesStoredP
225 #endif /* FS_STATS_DETAILED */
226                   );
227
228 #ifdef AFS_SGI_XFS_IOPS_ENV
229 #include <afs/xfsattrs.h>
230 static int GetLinkCount(Volume *avp, struct stat *astat)
231 {
232     if (!strcmp("xfs", astat->st_fstype)) {
233         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
234     }
235     else
236         return astat->st_nlink;
237 }
238 #else
239 #define GetLinkCount(V, S) (S)->st_nlink
240 #endif
241
242 afs_int32 SpareComp(Volume *avolp)
243 {
244     register afs_int32 temp;
245
246     FS_LOCK
247     if (PctSpare) {
248         temp = V_maxquota(avolp);
249         if (temp == 0) {
250             /* no matter; doesn't check in this case */
251             FS_UNLOCK
252             return 0;
253         }
254         temp = (temp * PctSpare) / 100;
255         FS_UNLOCK
256         return temp;
257     }
258     else {
259         FS_UNLOCK
260         return BlocksSpare;
261     }
262
263 } /*SpareComp*/
264
265 /*
266  * Set the volume synchronization parameter for this volume.  If it changes,
267  * the Cache Manager knows that the volume must be purged from the stat cache.
268  */
269 static void SetVolumeSync(register struct AFSVolSync *async, 
270                           register Volume *avol)
271 {
272     FS_LOCK
273     /* date volume instance was created */
274     if (async) {
275         if (avol)
276             async->spare1 = avol->header->diskstuff.creationDate;
277         else
278             async->spare1 = 0;
279         async->spare2 = 0;
280         async->spare3 = 0;
281         async->spare4 = 0;
282         async->spare5 = 0;
283         async->spare6 = 0;
284     }
285     FS_UNLOCK
286 } /*SetVolumeSync*/
287
288 /*
289  * Note that this function always returns a held host, so
290  * that CallPostamble can block without the host's disappearing.
291  * Call returns rx connection in passed in *tconn
292  */
293 static int CallPreamble(register struct rx_call *acall, int activecall,
294                         struct rx_connection **tconn)
295 {
296     struct host *thost;
297     struct client *tclient;
298     int retry_flag=1;
299     int code = 0;
300     char hoststr[16];
301     if (!tconn) {
302         ViceLog (0, ("CallPreamble: unexpected null tconn!\n"));
303         return -1;
304     }
305     *tconn = rx_ConnectionOf(acall);
306
307     H_LOCK
308 retry:
309     tclient = h_FindClient_r(*tconn);
310     if (tclient->prfail == 1) { /* couldn't get the CPS */
311        if (!retry_flag) {
312           h_ReleaseClient_r(tclient);
313           ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
314           H_UNLOCK
315           return -1001;
316        }
317        retry_flag=0;    /* Retry once */
318
319        /* Take down the old connection and re-read the key file */
320        ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
321        H_UNLOCK
322        code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
323        H_LOCK
324        if (code) {
325           h_ReleaseClient_r(tclient);
326           H_UNLOCK
327           ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
328           return -1001;
329        }
330
331        tclient->prfail = 2;      /* Means re-eval client's cps */
332        h_ReleaseClient_r(tclient);
333        goto retry;
334     }
335
336     thost = tclient->host;
337     tclient->LastCall = thost->LastCall = FT_ApproxTime();
338     if (activecall) /* For all but "GetTime" calls */
339         thost->ActiveCall = thost->LastCall;
340
341     h_Lock_r(thost);
342     if (thost->hostFlags & HOSTDELETED) {
343       ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
344       code = VBUSY; /* raced, so retry */
345     }
346     else if ((thost->hostFlags & VENUSDOWN) || (thost->hostFlags & HFE_LATER)){
347       if (BreakDelayedCallBacks_r(thost)) {
348         ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP.  Possible network or routing failure.\n",
349                 afs_inet_ntoa_r(thost->host, hoststr)));
350         if ( MultiProbeAlternateAddress_r (thost) ) {
351             ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
352                         afs_inet_ntoa_r(thost->host, hoststr), 
353                         ntohs(thost->port)));
354             code = -1;
355         } else {
356             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
357                         afs_inet_ntoa_r(thost->host, hoststr), 
358                         ntohs(thost->port)));
359             if (BreakDelayedCallBacks_r(thost)) {
360                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
361                         afs_inet_ntoa_r(thost->host, hoststr)));
362                 code = -1;
363             }
364         }
365       }
366     } else {
367        code =  0;
368     }
369
370     h_ReleaseClient_r(tclient);
371     h_Unlock_r(thost);
372     H_UNLOCK
373     return code;      
374
375 } /*CallPreamble*/
376
377
378 static afs_int32 CallPostamble(register struct rx_connection *aconn,
379                                afs_int32 ret)
380 {
381     struct host *thost;
382     struct client *tclient;
383     int translate = 0;
384
385     H_LOCK
386     tclient = h_FindClient_r(aconn);
387     thost = tclient->host;
388     if (thost->hostFlags & HERRORTRANS) translate = 1;
389     h_ReleaseClient_r(tclient);
390     h_Release_r(thost);
391     H_UNLOCK
392
393     return (translate ? sys_error_to_et(ret) : ret);
394 } /*CallPostamble*/
395
396 /*
397  * Returns the volume and vnode pointers associated with file Fid; the lock
398  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
399  * are incremented and they must be eventualy released.
400  */
401 static afs_int32
402 CheckVnode(AFSFid *fid, Volume **volptr, Vnode **vptr, int lock)
403 {
404     int fileCode = 0;
405     int errorCode = -1;
406     static struct timeval restartedat = {0,0};
407
408     if (fid->Volume == 0 || fid->Vnode == 0) /* not: || fid->Unique == 0) */
409         return(EINVAL);
410     if ((*volptr) == 0) {
411       extern int VInit;
412
413       while(1) {
414         errorCode = 0;
415         *volptr = VGetVolume(&errorCode, (afs_int32)fid->Volume);
416         if (!errorCode) {
417           assert (*volptr);
418           break;
419         }
420         if ((errorCode == VOFFLINE) && (VInit < 2)) {
421             /* The volume we want may not be attached yet because
422              * the volume initialization is not yet complete.
423              * We can do several things: 
424              *     1.  return -1, which will cause users to see
425              *         "connection timed out".  This is more or
426              *         less the same as always, except that the servers
427              *         may appear to bounce up and down while they
428              *         are actually restarting.
429              *     2.  return VBUSY which will cause clients to 
430              *         sleep and retry for 6.5 - 15 minutes, depending
431              *         on what version of the CM they are running.  If
432              *         the file server takes longer than that interval 
433              *         to attach the desired volume, then the application
434              *         will see an ENODEV or EIO.  This approach has 
435              *         the advantage that volumes which have been attached
436              *         are immediately available, it keeps the server's
437              *         immediate backlog low, and the call is interruptible
438              *         by the user.  Users see "waiting for busy volume."
439              *     3.  sleep here and retry.  Some people like this approach
440              *         because there is no danger of seeing errors.  However, 
441              *         this approach only works with a bounded number of 
442              *         clients, since the pending queues will grow without
443              *         stopping.  It might be better to find a way to take
444              *         this call and stick it back on a queue in order to
445              *         recycle this thread for a different request.    
446              *     4.  Return a new error code, which new cache managers will
447              *         know enough to interpret as "sleep and retry", without
448              *         the upper bound of 6-15 minutes that is imposed by the
449              *         VBUSY handling.  Users will see "waiting for
450              *         busy volume," so they know that something is
451              *         happening.  Old cache managers must be able to do  
452              *         something reasonable with this, for instance, mark the
453              *         server down.  Fortunately, any error code < 0
454              *         will elicit that behavior. See #1.
455              *     5.  Some combination of the above.  I like doing #2 for 10
456              *         minutes, followed by #4.  3.1b and 3.2 cache managers
457              *         will be fine as long as the restart period is
458              *         not longer than 6.5 minutes, otherwise they may
459              *         return ENODEV to users.  3.3 cache managers will be
460              *         fine for 10 minutes, then will return
461              *         ETIMEDOUT.  3.4 cache managers will just wait
462              *         until the call works or fails definitively.
463              *  NB. The problem with 2,3,4,5 is that old clients won't
464              *  fail over to an alternate read-only replica while this
465              *  server is restarting.  3.4 clients will fail over right away.
466              */
467           if (restartedat.tv_sec == 0) {
468             /* I'm not really worried about when we restarted, I'm   */
469             /* just worried about when the first VBUSY was returned. */
470             TM_GetTimeOfDay(&restartedat, 0);
471             return(busyonrst?VBUSY:VRESTARTING);
472           }
473           else {
474             struct timeval now;
475             TM_GetTimeOfDay(&now, 0);
476             if ((now.tv_sec - restartedat.tv_sec) < (11*60)) {
477               return(busyonrst?VBUSY:VRESTARTING);
478             }
479             else {
480               return (VRESTARTING);
481             }
482           }
483         }
484           /* allow read operations on busy volume */
485         else if(errorCode==VBUSY && lock==READ_LOCK) {
486           errorCode=0;
487           break;
488         }
489         else if (errorCode)
490           return(errorCode);
491       }
492     }
493     assert (*volptr);
494
495     /* get the vnode  */
496     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
497     if (errorCode)
498         return(errorCode);
499     if ((*vptr)->disk.uniquifier != fid->Unique) {
500         VPutVnode(&fileCode, *vptr);
501         assert(fileCode == 0);
502         *vptr = 0;
503         return(VNOVNODE);   /* return the right error code, at least */
504     }
505     return(0);
506 } /*CheckVnode*/
507
508 /*
509  * This routine returns the ACL associated with the targetptr. If the
510  * targetptr isn't a directory, we access its parent dir and get the ACL
511  * thru the parent; in such case the parent's vnode is returned in
512  * READ_LOCK mode.
513  */
514 static afs_int32
515 SetAccessList(Vnode **targetptr,
516               Volume **volume,
517               struct acl_accessList **ACL,
518               int * ACLSize,
519               Vnode **parent,
520               AFSFid *Fid,
521               int Lock)
522 {
523     if ((*targetptr)->disk.type == vDirectory) {
524         *parent = 0;
525         *ACL = VVnodeACL(*targetptr);
526         *ACLSize = VAclSize(*targetptr);
527         return(0);
528     }
529     else {
530         assert(Fid != 0);
531         while(1) {
532             VnodeId parentvnode;
533             int errorCode = 0;
534             
535             parentvnode = (*targetptr)->disk.parent;
536             VPutVnode(&errorCode,*targetptr);
537             *targetptr = 0;
538             if (errorCode) return(errorCode);
539             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
540             if (errorCode) return(errorCode);
541             *ACL = VVnodeACL(*parent);
542             *ACLSize = VAclSize(*parent);
543             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
544                 return(errorCode);
545             if ((*targetptr)->disk.parent != parentvnode) {
546                 VPutVnode(&errorCode, *parent);
547                 *parent = 0;
548                 if (errorCode) return(errorCode);
549             } else
550                 return(0);
551         }
552     }
553
554 } /*SetAccessList*/
555
556 /*
557  * Compare the directory's ACL with the user's access rights in the client
558  * connection and return the user's and everybody else's access permissions
559  * in rights and anyrights, respectively
560  */
561 static afs_int32
562 GetRights (struct client *client,
563            struct acl_accessList *ACL,
564            afs_int32 *rights,
565            afs_int32 *anyrights)
566 {
567     extern prlist SystemAnyUserCPS;
568     afs_int32 hrights = 0;
569     int code;
570
571     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
572
573         ViceLog(0,("CheckRights failed\n"));
574         *anyrights = 0;
575     }
576     *rights = 0;
577     acl_CheckRights(ACL, &client->CPS, rights);
578
579         /* wait if somebody else is already doing the getCPS call */
580     H_LOCK
581     while ( client->host->hostFlags & HCPS_INPROGRESS )
582     {
583         client->host->hostFlags |= HCPS_WAITING;  /* I am waiting */
584 #ifdef AFS_PTHREAD_ENV
585         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
586 #else /* AFS_PTHREAD_ENV */
587         if ((code=LWP_WaitProcess( &(client->host->hostFlags))) !=LWP_SUCCESS)
588                 ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
589 #endif /* AFS_PTHREAD_ENV */
590     }
591
592     if (client->host->hcps.prlist_len && !client->host->hcps.prlist_val) {
593         ViceLog(0,("CheckRights: len=%d, for host=0x%x\n", client->host->hcps.prlist_len, client->host->host));
594     } else
595         acl_CheckRights(ACL, &client->host->hcps, &hrights);
596     H_UNLOCK
597     /* Allow system:admin the rights given with the -implicit option */
598     if (acl_IsAMember(SystemId, &client->CPS))
599         *rights |= implicitAdminRights;
600     *rights |= hrights;
601     *anyrights |= hrights;
602
603     return(0);
604
605 } /*GetRights*/
606
607 /*
608  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
609  * a System:Administrator)
610  */
611 static afs_int32
612 VanillaUser(struct client *client)
613 {
614     if (acl_IsAMember(SystemId, &client->CPS))
615         return(0);  /* not a system administrator, then you're "vanilla" */
616     return(1);
617
618 } /*VanillaUser*/
619
620
621 /*
622  * This unusual afs_int32-parameter routine encapsulates all volume package related
623  * operations together in a single function; it's called by almost all AFS
624  * interface calls.
625  */
626 static afs_int32
627 GetVolumePackage(struct rx_connection *tcon,
628                  AFSFid *Fid,
629                  Volume **volptr,
630                  Vnode **targetptr,
631                  int chkforDir,
632                  Vnode **parent,
633                  struct client **client,
634                  int locktype,
635                  afs_int32 *rights, 
636                  afs_int32 *anyrights)
637 {
638     struct acl_accessList * aCL;    /* Internal access List */
639     int aCLSize;            /* size of the access list */
640     int errorCode = 0;      /* return code to caller */
641
642     if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
643         return(errorCode);
644     if (chkforDir) {
645         if (chkforDir == MustNOTBeDIR && ((*targetptr)->disk.type == vDirectory))
646             return(EISDIR);
647         else if (chkforDir == MustBeDIR && ((*targetptr)->disk.type != vDirectory))
648             return(ENOTDIR);
649     }
650     if ((errorCode = SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent, (chkforDir == MustBeDIR ? (AFSFid *)0 : Fid), (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
651         return(errorCode);
652     if (chkforDir == MustBeDIR) assert((*parent) == 0);
653     if ((errorCode = GetClient(tcon, client)) != 0)
654         return(errorCode);
655     if (!(*client))
656         return(EINVAL);
657     assert(GetRights(*client, aCL, rights, anyrights) == 0);
658     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
659     if ((*targetptr)->disk.type != vDirectory) {
660         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
661         if ((*targetptr)->disk.owner == (*client)->ViceId)
662             (*rights) |= PRSFS_ADMINISTER;
663         else
664             (*rights) &= ~PRSFS_ADMINISTER;
665     }
666 #ifdef ADMIN_IMPLICIT_LOOKUP
667     /* admins get automatic lookup on everything */
668     if (!VanillaUser(*client)) (*rights) |= PRSFS_LOOKUP;
669 #endif /* ADMIN_IMPLICIT_LOOKUP */
670     return errorCode;
671
672 } /*GetVolumePackage*/
673
674
675 /*
676  * This is the opposite of GetVolumePackage(), and is always used at the end of
677  * AFS calls to put back all used vnodes and the volume in the proper order!
678  */
679 static afs_int32
680 PutVolumePackage(Vnode *parentwhentargetnotdir, 
681                  Vnode *targetptr,
682                  Vnode *parentptr,
683                  Volume *volptr)
684 {
685     int fileCode = 0;   /* Error code returned by the volume package */
686
687     if (parentwhentargetnotdir) {
688         VPutVnode(&fileCode, parentwhentargetnotdir);
689         assert(!fileCode || (fileCode == VSALVAGE));
690     }
691     if (targetptr) {
692         VPutVnode(&fileCode, targetptr);
693         assert(!fileCode || (fileCode == VSALVAGE));
694     }
695     if (parentptr) {
696         VPutVnode(&fileCode, parentptr);
697         assert(!fileCode || (fileCode == VSALVAGE));
698     }
699     if (volptr) {
700         VPutVolume(volptr);
701     }
702 } /*PutVolumePackage*/
703
704 static int VolumeOwner (register struct client *client, 
705                         register Vnode *targetptr)
706 {
707     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
708
709     if (owner >= 0)
710         return (client->ViceId == owner);
711     else {
712         /* 
713          * We don't have to check for host's cps since only regular
714          * viceid are volume owners.
715          */
716         return (acl_IsAMember(owner, &client->CPS));
717     }
718
719 } /*VolumeOwner*/
720
721 static int VolumeRootVnode (Vnode *targetptr)
722 {
723     return ((targetptr->vnodeNumber == ROOTVNODE) &&
724             (targetptr->disk.uniquifier == 1));
725
726 } /*VolumeRootVnode*/
727
728 /*
729  * Check if target file has the proper access permissions for the Fetch
730  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
731  * StoreStatus) related calls
732  */
733 /* this code should probably just set a "priv" flag where all the audit events
734  * are now, and only generate the audit event once at the end of the routine, 
735  * thus only generating the event if all the checks succeed, but only because
736  * of the privilege       XXX
737  */
738 static afs_int32
739 Check_PermissionRights(Vnode *targetptr,
740                        struct client *client,
741                        afs_int32 rights,
742                        int CallingRoutine,
743                        AFSStoreStatus *InStatus)
744 {
745     int errorCode = 0;
746 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
747 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
748 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
749
750     if (CallingRoutine & CHK_FETCH) {
751         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) 
752           {
753             if (targetptr->disk.type == vDirectory || targetptr->disk.type == vSymlink) {
754                 if (   !(rights & PRSFS_LOOKUP)
755 #ifdef ADMIN_IMPLICIT_LOOKUP  
756                     /* grant admins fetch on all directories */
757                     && VanillaUser(client)
758 #endif /* ADMIN_IMPLICIT_LOOKUP */
759                     && !VolumeOwner(client, targetptr))
760                     return(EACCES);
761             } else {    /* file */
762                 /* must have read access, or be owner and have insert access */
763                 if (!(rights & PRSFS_READ) &&
764                     !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
765                     return(EACCES);
766             }
767             if (CallingRoutine == CHK_FETCHDATA && targetptr->disk.type == vFile)
768 #ifdef USE_GROUP_PERMS
769                 if (!OWNSp(client, targetptr) &&
770                     !acl_IsAMember(targetptr->disk.owner, &client->CPS)) {
771                     errorCode = (((GROUPREAD|GROUPEXEC) & targetptr->disk.modeBits)
772                                  ? 0: EACCES);
773                 } else {
774                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits)
775                                 ? 0: EACCES);
776                 }
777 #else
778                 /*
779                  * The check with the ownership below is a kludge to allow
780                  * reading of files created with no read permission. The owner
781                  * of the file is always allowed to read it.
782                  */
783                 if ((client->ViceId != targetptr->disk.owner) && VanillaUser(client))
784                     errorCode =(((OWNERREAD|OWNEREXEC) & targetptr->disk.modeBits) ? 0: EACCES);
785 #endif
786         }
787         else /*  !VanillaUser(client) && !FetchData */ {
788           osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
789                                         AUD_INT, CallingRoutine, AUD_END);
790         }
791     }
792     else { /* a store operation */
793       if ( (rights & PRSFS_INSERT) && OWNSp(client, targetptr)
794           && (CallingRoutine != CHK_STOREACL)
795           && (targetptr->disk.type == vFile))
796         {
797           /* bypass protection checks on first store after a create
798            * for the creator; also prevent chowns during this time
799            * unless you are a system administrator */
800           /******  InStatus->Owner && UnixModeBits better be SET!! */
801           if ( CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
802             if (readonlyServer) 
803               return(VREADONLY);
804             else if (VanillaUser (client)) 
805               return(EPERM);      /* Was EACCES */
806             else
807               osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0), 
808                                             AUD_INT, CallingRoutine, AUD_END);
809           }
810         } else {
811           if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
812             osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
813                                           AUD_INT, CallingRoutine, AUD_END);
814           }
815           else {
816             if (readonlyServer) {
817                 return(VREADONLY);
818             }
819             if (CallingRoutine == CHK_STOREACL) {
820               if (!(rights & PRSFS_ADMINISTER) &&
821                   !VolumeOwner(client, targetptr)) return(EACCES);
822             }
823             else {      /* store data or status */
824               /* watch for chowns and chgrps */
825               if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
826                 if (readonlyServer) 
827                   return(VREADONLY);
828                 else if (VanillaUser (client)) 
829                   return(EPERM);        /* Was EACCES */
830                 else
831                   osi_audit(PrivilegeEvent, 0,
832                             AUD_INT, (client ? client->ViceId : 0), 
833                             AUD_INT, CallingRoutine, AUD_END);
834               }
835               /* must be sysadmin to set suid/sgid bits */
836               if ((InStatus->Mask & AFS_SETMODE) &&
837 #ifdef AFS_NT40_ENV
838                   (InStatus->UnixModeBits & 0xc00) != 0) {
839 #else
840                   (InStatus->UnixModeBits & (S_ISUID|S_ISGID)) != 0) {
841 #endif
842                 if (readonlyServer)
843                   return(VREADONLY);
844                 if (VanillaUser(client))
845                   return(EACCES);
846                 else osi_audit( PrivSetID, 0, AUD_INT, (client ? client->ViceId : 0),
847                                               AUD_INT, CallingRoutine, AUD_END);
848               }
849               if (CallingRoutine == CHK_STOREDATA) {
850                 if (readonlyServer)
851                   return(VREADONLY);
852                 if (!(rights & PRSFS_WRITE))
853                   return(EACCES);
854                 /* Next thing is tricky.  We want to prevent people
855                  * from writing files sans 0200 bit, but we want
856                  * creating new files with 0444 mode to work.  We
857                  * don't check the 0200 bit in the "you are the owner"
858                  * path above, but here we check the bit.  However, if
859                  * you're a system administrator, we ignore the 0200
860                  * bit anyway, since you may have fchowned the file,
861                  * too */
862 #ifdef USE_GROUP_PERMS
863                         if ((targetptr->disk.type == vFile)
864                             && VanillaUser(client)) {
865                             if (!OWNSp(client, targetptr) &&
866                                 !acl_IsAMember(targetptr->disk.owner,
867                                                &client->CPS)) {
868                                 errorCode = ((GROUPWRITE & targetptr->disk.modeBits)
869                                              ? 0: EACCES);
870                             } else {
871                                 errorCode = ((OWNERWRITE & targetptr->disk.modeBits)
872                                              ? 0 : EACCES);
873                             }
874                         } else
875 #endif
876                 if ((targetptr->disk.type != vDirectory)
877                     && (!(targetptr->disk.modeBits & OWNERWRITE)))
878                   if (readonlyServer)
879                     return(VREADONLY);
880                   if (VanillaUser(client))
881                     return(EACCES);
882                   else osi_audit( PrivilegeEvent, 0, AUD_INT, (client ? client->ViceId : 0),
883                                                      AUD_INT, CallingRoutine, AUD_END);
884               }
885               else {  /* a status store */
886                 if (readonlyServer)
887                   return(VREADONLY);
888                 if (targetptr->disk.type == vDirectory) {
889                   if (!(rights & PRSFS_DELETE) && !(rights & PRSFS_INSERT))
890                     return(EACCES);
891                 }
892                 else {  /* a file  or symlink */
893                   if (!(rights & PRSFS_WRITE)) return(EACCES);
894                 }
895               }
896             }
897           }
898         }
899     }
900     return(errorCode);
901
902 } /*Check_PermissionRights*/
903
904
905 /*
906  * The Access List information is converted from its internal form in the
907  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
908  * external form and returned back to the caller, via the AccessList
909  * structure
910  */
911 static afs_int32
912 RXFetch_AccessList(Vnode *targetptr,
913                    Vnode *parentwhentargetnotdir,
914                    struct AFSOpaque *AccessList)
915 {
916     char * eACL;        /* External access list placeholder */
917
918     if (acl_Externalize((targetptr->disk.type == vDirectory ?
919                          VVnodeACL(targetptr) :
920                          VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
921         return EIO;
922     }
923     if ((strlen(eACL)+1) > AFSOPAQUEMAX) {
924         acl_FreeExternalACL(&eACL);
925         return(E2BIG);
926     } else {
927         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
928         AccessList->AFSOpaque_len = strlen(eACL) +1;
929     }
930     acl_FreeExternalACL(&eACL);
931     return(0);
932
933 } /*RXFetch_AccessList*/
934
935
936 /*
937  * The Access List information is converted from its external form in the
938  * input AccessList structure to the internal representation and copied into
939  * the target dir's vnode storage.
940  */
941 static afs_int32
942 RXStore_AccessList(Vnode *targetptr, struct AFSOpaque *AccessList)
943 {
944     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
945
946     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
947         return(EINVAL);
948     if ((newACL->size + 4) > VAclSize(targetptr))
949         return(E2BIG);
950     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
951     acl_FreeACL(&newACL);
952     return(0);
953
954 } /*RXStore_AccessList*/
955
956
957 static afs_int32
958 Fetch_AccessList(Vnode *targetptr, Vnode *parentwhentargetnotdir,
959                  struct AFSAccessList *AccessList)
960 {
961     char * eACL;        /* External access list placeholder */
962
963     assert(acl_Externalize((targetptr->disk.type == vDirectory ?
964                             VVnodeACL(targetptr) :
965                             VVnodeACL(parentwhentargetnotdir)), &eACL) == 0);
966     if ((strlen(eACL)+1) > AccessList->MaxSeqLen) {
967         acl_FreeExternalACL(&eACL);
968         return(E2BIG);
969     } else {
970         strcpy((char *)(AccessList->SeqBody), (char *)eACL);
971         AccessList->SeqLen = strlen(eACL) +1;
972     }
973     acl_FreeExternalACL(&eACL);
974     return(0);
975
976 } /*Fetch_AccessList*/
977
978 /*
979  * The Access List information is converted from its external form in the
980  * input AccessList structure to the internal representation and copied into
981  * the target dir's vnode storage.
982  */
983 static afs_int32
984 Store_AccessList(Vnode *targetptr, struct AFSAccessList *AccessList)
985 {
986     struct acl_accessList * newACL;     /* PlaceHolder for new access list */
987
988     if (acl_Internalize(AccessList->SeqBody, &newACL) != 0)
989         return(EINVAL);
990     if ((newACL->size + 4) > VAclSize(targetptr))
991         return(E2BIG);
992     memcpy((char *) VVnodeACL(targetptr), (char *) newACL, (int)(newACL->size));
993     acl_FreeACL(&newACL);
994     return(0);
995
996 } /*Store_AccessList*/
997
998
999 /* In our current implementation, each successive data store (new file
1000  * data version) creates a new inode. This function creates the new
1001  * inode, copies the old inode's contents to the new one, remove the old
1002  * inode (i.e. decrement inode count -- if it's currently used the delete
1003  * will be delayed), and modify some fields (i.e. vnode's
1004  * disk.inodeNumber and cloned)
1005  */
1006 #define COPYBUFFSIZE    8192
1007 static int CopyOnWrite(Vnode *targetptr, Volume *volptr)
1008 {
1009     Inode       ino, nearInode;
1010     int         rdlen;
1011     int         wrlen;
1012     register 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     errorCode = CallPostamble(tcon, errorCode);
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     errorCode = CallPostamble(tcon, errorCode);
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     errorCode = CallPostamble(tcon, errorCode);
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     errorCode = CallPostamble(tcon, errorCode);
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     code = CallPostamble(tcon, code);
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     errorCode = CallPostamble(tcon, errorCode);
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     errorCode = CallPostamble(tcon, errorCode);
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     code = CallPostamble(tcon, code);
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     code = CallPostamble(tcon, code);
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     code = CallPostamble(tcon, code);
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,
4038      * but possible.  We could try to put the old file back, but it is
4039      * highly unlikely that it would work since it would involve issuing
4040      * another create.
4041      */
4042     if ((errorCode = Create(&newdir,(char *) NewName, &fileFid)))
4043         goto Bad_Rename;
4044
4045     /* Delete the old name */
4046     assert(Delete(&olddir,(char *) OldName) == 0);
4047
4048     /* if the directory length changes, reflect it in the statistics */
4049 #if FS_STATS_DETAILED
4050     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4051                              oldvptr->disk.linkCount, client->InSameNetwork);
4052     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4053                              newvptr->disk.linkCount, client->InSameNetwork);
4054 #else
4055     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
4056                              oldvptr->disk.linkCount);
4057     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
4058                              newvptr->disk.linkCount);
4059 #endif /* FS_STATS_DETAILED */
4060
4061     if (oldvptr == newvptr)
4062         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
4063
4064     fileptr->disk.parent = newvptr->vnodeNumber;
4065     fileptr->changed_newTime = 1;       /* status change of moved file */
4066
4067     /* if we are dealing with a rename of a directory */
4068     if (fileptr->disk.type == vDirectory) {
4069         assert(!fileptr->disk.cloned);          
4070         SetDirHandle(&filedir, fileptr);
4071         /* fix .. to point to the correct place */
4072         Delete(&filedir, ".."); /* No assert--some directories may be bad */
4073         assert(Create(&filedir, "..", NewDirFid) == 0);
4074         fileptr->disk.dataVersion++;
4075         /* if the parent directories are different the link counts have to be   */
4076         /* changed due to .. in the renamed directory */
4077         if (oldvptr != newvptr) {
4078             oldvptr->disk.linkCount--;
4079             newvptr->disk.linkCount++;
4080         }
4081     }
4082
4083     /* set up return status */
4084     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, 0);
4085     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, 0);
4086     if (newfileptr && doDelete) {
4087         DeleteFileCallBacks(&newFileFid);       /* no other references */
4088     }
4089
4090     DFlush();
4091
4092     /* convert the write locks to a read locks before breaking callbacks */
4093     VVnodeWriteToRead(&errorCode, newvptr);
4094     assert(!errorCode || errorCode == VSALVAGE);
4095     if (oldvptr != newvptr) {
4096         VVnodeWriteToRead(&errorCode, oldvptr);
4097         assert(!errorCode || errorCode == VSALVAGE);
4098     }
4099     if (newfileptr && !doDelete) {
4100         /* convert the write lock to a read lock before breaking callbacks */
4101         VVnodeWriteToRead(&errorCode, newfileptr);
4102         assert(!errorCode || errorCode == VSALVAGE);
4103     }
4104
4105     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
4106     BreakCallBack(client->host, NewDirFid, 0);
4107     if (oldvptr != newvptr) {
4108         BreakCallBack(client->host, OldDirFid, 0);
4109         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
4110             BreakCallBack(client->host, &fileFid, 0);
4111     }
4112     if (newfileptr) {
4113         /* Note:  it is not necessary to break the callback */
4114         if (doDelete)
4115             DeleteFileCallBacks(&newFileFid);   /* no other references */
4116         else
4117             /* other's still exist (with wrong link count) */
4118             BreakCallBack(client->host, &newFileFid, 1);
4119     }
4120
4121 Bad_Rename: 
4122     if (newfileptr) {
4123         VPutVnode(&fileCode, newfileptr);
4124         assert(fileCode == 0);
4125     }
4126     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
4127                      oldvptr, volptr);
4128     FidZap(&olddir);
4129     FidZap(&newdir);
4130     FidZap(&filedir);
4131     FidZap(&newfiledir);
4132     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
4133     return errorCode;
4134
4135 } /*SAFSS_Rename*/
4136
4137
4138 afs_int32 SRXAFS_Rename (struct rx_call *acall,              
4139                          struct AFSFid *OldDirFid,                   
4140                          char *OldName,                      
4141                          struct AFSFid *NewDirFid,
4142                          char *NewName,
4143                          struct AFSFetchStatus *OutOldDirStatus,
4144                          struct AFSFetchStatus *OutNewDirStatus,
4145                          struct AFSVolSync *Sync)
4146 {
4147     afs_int32 code;
4148     struct rx_connection *tcon;
4149 #if FS_STATS_DETAILED
4150     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4151     struct timeval opStartTime,
4152                    opStopTime;              /* Start/stop times for RPC op*/
4153     struct timeval elapsedTime;             /* Transfer time */
4154
4155     /*
4156      * Set our stats pointer, remember when the RPC operation started, and
4157      * tally the operation.
4158      */
4159     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
4160     FS_LOCK
4161     (opP->numOps)++;
4162     FS_UNLOCK
4163     TM_GetTimeOfDay(&opStartTime, 0);
4164 #endif /* FS_STATS_DETAILED */
4165
4166     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4167         goto Bad_Rename;
4168
4169     code = SAFSS_Rename (acall, OldDirFid, OldName, NewDirFid, NewName,
4170                          OutOldDirStatus, OutNewDirStatus, Sync);
4171
4172 Bad_Rename:    
4173     code = CallPostamble(tcon, code);
4174
4175 #if FS_STATS_DETAILED
4176     TM_GetTimeOfDay(&opStopTime, 0);
4177     if (code == 0) {
4178       FS_LOCK
4179       (opP->numSuccesses)++;
4180       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4181       fs_stats_AddTo((opP->sumTime), elapsedTime);
4182       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4183       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4184         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4185       }
4186       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4187         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4188       }
4189       FS_UNLOCK
4190     }
4191
4192 #endif /* FS_STATS_DETAILED */
4193
4194     osi_auditU (acall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
4195     return code;
4196
4197 } /*SRXAFS_Rename*/
4198
4199
4200 /*
4201  * This routine is called exclusively by SRXAFS_Symlink(), and should be
4202  * merged into it when possible.
4203  */
4204 static afs_int32 
4205 SAFSS_Symlink (struct rx_call *acall,
4206                struct AFSFid *DirFid,
4207                char *Name,
4208                char *LinkContents,
4209                struct AFSStoreStatus *InStatus,
4210                struct AFSFid *OutFid,
4211                struct AFSFetchStatus *OutFidStatus,
4212                struct AFSFetchStatus *OutDirStatus,
4213                struct AFSVolSync *Sync)         
4214
4215 {
4216     Vnode * parentptr = 0;              /* vnode of input Directory */
4217     Vnode * targetptr = 0;              /* vnode of the new link */
4218     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4219     int     errorCode = 0;              /* error code */
4220     int code = 0;
4221     DirHandle dir;                      /* Handle for dir package I/O */
4222     Volume * volptr = 0;                /* pointer to the volume header */
4223     struct client * client;             /* pointer to client structure */
4224     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
4225     struct client *t_client;            /* tmp ptr to client data */
4226     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4227     FdHandle_t *fdP;
4228     struct rx_connection *tcon = rx_ConnectionOf(acall);
4229
4230     FidZero(&dir);
4231
4232     /* Get ptr to client data for user Id for logging */
4233     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4234     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4235     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
4236             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4237             inet_ntoa(logHostAddr), t_client->ViceId));
4238     FS_LOCK
4239     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
4240     FS_UNLOCK
4241     if (!FileNameOK(Name)) {
4242         errorCode = EINVAL;
4243         goto Bad_SymLink;
4244     }
4245
4246     /*
4247      * Get the vnode and volume for the parent dir along with the caller's
4248      * rights to it
4249      */
4250     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4251                                      MustBeDIR, &parentwhentargetnotdir,
4252                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4253         goto Bad_SymLink;
4254     }
4255
4256     /* set volume synchronization information */
4257     SetVolumeSync(Sync, volptr);
4258
4259     /* Does the caller has insert (and write) access to the parent directory? */
4260     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4261         goto Bad_SymLink;
4262     }
4263
4264     /*
4265      * If we're creating a mount point (any x bits clear), we must have
4266      * administer access to the directory, too.  Always allow sysadmins
4267      * to do this.
4268      */
4269     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
4270         if (readonlyServer) {
4271             errorCode = VREADONLY;
4272             goto Bad_SymLink;
4273         }
4274         /*
4275          * We have a mountpoint, 'cause we're trying to set the Unix mode
4276          * bits to something with some x bits missing (default mode bits
4277          * if AFS_SETMODE is false is 0777)
4278          */
4279         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
4280             errorCode = EACCES;
4281             goto Bad_SymLink;
4282         }
4283     }
4284  
4285     /* get a new vnode for the symlink and set it up */
4286     if ((errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
4287                                    Name, OutFid, vSymlink,
4288                                    nBlocks(strlen((char *) LinkContents))))) {
4289         goto Bad_SymLink;
4290     }
4291
4292     /* update the status of the parent vnode */
4293 #if FS_STATS_DETAILED
4294     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4295                              parentptr->disk.linkCount, client->InSameNetwork);
4296 #else
4297     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4298                              parentptr->disk.linkCount);
4299 #endif /* FS_STATS_DETAILED */
4300
4301     /* update the status of the new symbolic link file vnode */
4302     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
4303                              volptr, (afs_size_t)strlen((char *)LinkContents));
4304
4305     /* Write the contents of the symbolic link name into the target inode */
4306     fdP = IH_OPEN(targetptr->handle);
4307     assert(fdP != NULL);
4308     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
4309     FDH_CLOSE(fdP);
4310     /*
4311      * Set up and return modified status for the parent dir and new symlink
4312      * to caller.
4313      */
4314     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4315     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4316
4317     /* convert the write lock to a read lock before breaking callbacks */
4318     VVnodeWriteToRead(&errorCode, parentptr);
4319     assert(!errorCode || errorCode == VSALVAGE);
4320
4321     /* break call back on the parent dir */
4322     BreakCallBack(client->host, DirFid, 0);
4323
4324 Bad_SymLink: 
4325     /* Write the all modified vnodes (parent, new files) and volume back */
4326     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4327     FidZap(&dir);
4328     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
4329     return errorCode;
4330
4331 } /*SAFSS_Symlink*/
4332
4333
4334 afs_int32 SRXAFS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
4335     struct AFSVolSync *Sync;
4336     struct rx_call *acall;               /* Rx call */
4337     struct AFSFid *DirFid;               /* Parent dir's fid */
4338     char *Name;                          /* File name to create */
4339     char *LinkContents;                  /* Contents of the new created file */
4340     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
4341     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
4342     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
4343     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
4344
4345 {
4346     afs_int32 code;
4347     struct rx_connection *tcon;
4348 #if FS_STATS_DETAILED
4349     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4350     struct timeval opStartTime,
4351                    opStopTime;              /* Start/stop times for RPC op*/
4352     struct timeval elapsedTime;             /* Transfer time */
4353
4354     /*
4355      * Set our stats pointer, remember when the RPC operation started, and
4356      * tally the operation.
4357      */
4358     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
4359     FS_LOCK
4360     (opP->numOps)++;
4361     FS_UNLOCK
4362     TM_GetTimeOfDay(&opStartTime, 0);
4363 #endif /* FS_STATS_DETAILED */
4364
4365     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4366         goto Bad_Symlink;
4367
4368     code = SAFSS_Symlink (acall, DirFid, Name, LinkContents, InStatus, OutFid,
4369                          OutFidStatus, OutDirStatus, Sync);
4370
4371 Bad_Symlink:    
4372     code = CallPostamble(tcon, code);
4373
4374 #if FS_STATS_DETAILED
4375     TM_GetTimeOfDay(&opStopTime, 0);
4376     if (code == 0) {
4377       FS_LOCK
4378       (opP->numSuccesses)++;
4379       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4380       fs_stats_AddTo((opP->sumTime), elapsedTime);
4381       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4382       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4383         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4384       }
4385       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4386         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4387       }
4388       FS_UNLOCK
4389     }
4390
4391 #endif /* FS_STATS_DETAILED */
4392
4393     osi_auditU (acall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4394     return code;
4395
4396 } /*SRXAFS_Symlink*/
4397
4398
4399 /*
4400  * This routine is called exclusively by SRXAFS_Link(), and should be
4401  * merged into it when possible.
4402  */
4403 static afs_int32 
4404 SAFSS_Link (struct rx_call *acall,
4405             struct AFSFid *DirFid,
4406             char *Name,
4407             struct AFSFid *ExistingFid,
4408             struct AFSFetchStatus *OutFidStatus,
4409             struct AFSFetchStatus *OutDirStatus,
4410             struct AFSVolSync *Sync)
4411 {
4412     Vnode * parentptr = 0;              /* vnode of input Directory */
4413     Vnode * targetptr = 0;              /* vnode of the new file */
4414     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4415     Volume * volptr = 0;                /* pointer to the volume header */
4416     int     errorCode = 0;              /* error code */
4417     DirHandle dir;                      /* Handle for dir package I/O */
4418     struct client * client;             /* pointer to client structure */
4419     afs_int32 rights, anyrights;                /* rights for this and any user */
4420     struct client *t_client;            /* tmp ptr to client data */
4421     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4422     struct rx_connection *tcon = rx_ConnectionOf(acall);
4423
4424     FidZero(&dir);
4425
4426     /* Get ptr to client data for user Id for logging */
4427     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4428     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4429     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
4430             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4431             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
4432             inet_ntoa(logHostAddr), t_client->ViceId));
4433     FS_LOCK
4434     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
4435     FS_UNLOCK
4436     if (DirFid->Volume != ExistingFid->Volume) {
4437         errorCode = EXDEV;
4438         goto Bad_Link;
4439     }
4440     if (!FileNameOK(Name)) {
4441         errorCode = EINVAL;
4442         goto Bad_Link;
4443     }
4444
4445     /*
4446      * Get the vnode and volume for the parent dir along with the caller's
4447      * rights to it
4448      */
4449     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4450                                      MustBeDIR, &parentwhentargetnotdir,
4451                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4452         goto Bad_Link;
4453     }
4454
4455     /* set volume synchronization information */
4456     SetVolumeSync(Sync, volptr);
4457
4458     /* Can the caller insert into the parent directory? */
4459     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4460         goto Bad_Link;
4461     }
4462
4463     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
4464         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
4465       /* AFS fileservers always have directory vnodes that are odd.   */
4466       errorCode = EISDIR;
4467       goto Bad_Link;
4468     }
4469
4470     /* get the file vnode  */
4471     if ((errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK))) {
4472         goto Bad_Link;
4473     }
4474     if (targetptr->disk.type != vFile) {
4475         errorCode = EISDIR;
4476         goto Bad_Link;
4477     }
4478     if (targetptr->disk.parent != DirFid->Vnode) {
4479         errorCode = EXDEV;
4480         goto Bad_Link;
4481     }
4482     if (parentptr->disk.cloned) 
4483     {
4484         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
4485         if ( ( errorCode = CopyOnWrite(parentptr, volptr)))
4486                 goto Bad_Link;          /* disk full error */
4487     }
4488
4489     /* add the name to the directory */
4490     SetDirHandle(&dir, parentptr);
4491     if ((errorCode = Create(&dir, (char *)Name, ExistingFid)))
4492         goto Bad_Link;
4493     DFlush();
4494
4495     /* update the status in the parent vnode */
4496     /**WARNING** --> disk.author SHOULDN'T be modified???? */
4497 #if FS_STATS_DETAILED
4498     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4499                              parentptr->disk.linkCount, client->InSameNetwork);
4500 #else
4501     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4502                              parentptr->disk.linkCount);
4503 #endif /* FS_STATS_DETAILED */
4504
4505     targetptr->disk.linkCount++;
4506     targetptr->disk.author = client->ViceId;
4507     targetptr->changed_newTime = 1; /* Status change of linked-to file */
4508
4509     /* set up return status */
4510     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4511     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
4512
4513     /* convert the write locks to read locks before breaking callbacks */
4514     VVnodeWriteToRead(&errorCode, targetptr);
4515     assert(!errorCode || errorCode == VSALVAGE);
4516     VVnodeWriteToRead(&errorCode, parentptr);
4517     assert(!errorCode || errorCode == VSALVAGE);
4518     
4519     /* break call back on DirFid */
4520     BreakCallBack(client->host, DirFid, 0);
4521     /*
4522      * We also need to break the callback for the file that is hard-linked since part 
4523      * of its status (like linkcount) is changed
4524      */
4525     BreakCallBack(client->host, ExistingFid, 0);
4526
4527 Bad_Link:
4528     /* Write the all modified vnodes (parent, new files) and volume back */
4529     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4530     FidZap(&dir);
4531     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
4532     return errorCode;
4533
4534 } /*SAFSS_Link*/
4535
4536
4537 afs_int32 SRXAFS_Link (struct rx_call *acall,
4538                        struct AFSFid *DirFid,
4539                        char *Name,
4540                        struct AFSFid *ExistingFid,
4541                        struct AFSFetchStatus *OutFidStatus,
4542                        struct AFSFetchStatus *OutDirStatus,
4543                        struct AFSVolSync *Sync)
4544 {
4545     afs_int32 code;
4546     struct rx_connection *tcon;
4547 #if FS_STATS_DETAILED
4548     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4549     struct timeval opStartTime,
4550                    opStopTime;              /* Start/stop times for RPC op*/
4551     struct timeval elapsedTime;             /* Transfer time */
4552
4553     /*
4554      * Set our stats pointer, remember when the RPC operation started, and
4555      * tally the operation.
4556      */
4557     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
4558     FS_LOCK
4559     (opP->numOps)++;
4560     FS_UNLOCK
4561     TM_GetTimeOfDay(&opStartTime, 0);
4562 #endif /* FS_STATS_DETAILED */
4563
4564     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4565         goto Bad_Link;
4566
4567     code = SAFSS_Link (acall, DirFid, Name, ExistingFid, OutFidStatus,
4568                       OutDirStatus, Sync);
4569     
4570 Bad_Link:
4571     code = CallPostamble(tcon, code);
4572
4573 #if FS_STATS_DETAILED
4574     TM_GetTimeOfDay(&opStopTime, 0);
4575     if (code == 0) {
4576       FS_LOCK
4577       (opP->numSuccesses)++;
4578       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4579       fs_stats_AddTo((opP->sumTime), elapsedTime);
4580       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4581       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4582         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4583       }
4584       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4585         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4586       }
4587       FS_UNLOCK
4588     }
4589
4590 #endif /* FS_STATS_DETAILED */
4591
4592     osi_auditU (acall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
4593     return code;
4594
4595 } /*SRXAFS_Link*/
4596
4597
4598 /*
4599  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
4600  * merged into it when possible.
4601  */
4602 static afs_int32
4603 SAFSS_MakeDir (struct rx_call *acall,
4604                struct AFSFid *DirFid,
4605                char *Name,
4606                struct AFSStoreStatus *InStatus,
4607                struct AFSFid *OutFid,
4608                struct AFSFetchStatus *OutFidStatus,
4609                struct AFSFetchStatus *OutDirStatus,
4610                struct AFSCallBack *CallBack,
4611                struct AFSVolSync *Sync)
4612
4613 {
4614     Vnode * parentptr = 0;              /* vnode of input Directory */
4615     Vnode * targetptr = 0;              /* vnode of the new file */
4616     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4617     Volume * volptr = 0;                /* pointer to the volume header */
4618     int     errorCode = 0;              /* error code */
4619     struct acl_accessList * newACL;     /* Access list */
4620     int     newACLSize;                 /* Size of access list */
4621     DirHandle dir;                      /* Handle for dir package I/O */
4622     DirHandle parentdir;                /* Handle for dir package I/O */
4623     struct client * client;             /* pointer to client structure */
4624     afs_int32 rights, anyrights;                /* rights for this and any user */
4625     struct client *t_client;            /* tmp ptr to client data */
4626     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4627     struct rx_connection *tcon = rx_ConnectionOf(acall);
4628
4629     FidZero(&dir);
4630     FidZero(&parentdir);
4631
4632     /* Get ptr to client data for user Id for logging */
4633     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4634     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4635     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4636             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4637             inet_ntoa(logHostAddr), t_client->ViceId));
4638     FS_LOCK
4639     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
4640     FS_UNLOCK
4641     if (!FileNameOK(Name)) {
4642         errorCode = EINVAL;
4643         goto Bad_MakeDir;
4644     }
4645
4646     /*
4647      * Get the vnode and volume for the parent dir along with the caller's
4648      * rights to it.
4649      */
4650     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4651                                      MustBeDIR, &parentwhentargetnotdir,
4652                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4653         goto Bad_MakeDir;
4654     }
4655  
4656     /* set volume synchronization information */
4657     SetVolumeSync(Sync, volptr);
4658
4659     /* Write access to the parent directory? */
4660 #ifdef DIRCREATE_NEED_WRITE
4661     /*
4662      * requires w access for the user to create a directory. this
4663      * closes a loophole in the current security arrangement, since a
4664      * user with i access only can create a directory and get the
4665      * implcit a access that goes with dir ownership, and proceed to 
4666      * subvert quota in the volume.
4667      */
4668     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
4669         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
4670 #else 
4671     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
4672 #endif /* DIRCREATE_NEED_WRITE */ 
4673         goto Bad_MakeDir;
4674     }
4675
4676 #define EMPTYDIRBLOCKS 2
4677     /* get a new vnode and set it up */
4678     if ((errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
4679                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS))) {
4680         goto Bad_MakeDir;
4681     }
4682
4683     /* Update the status for the parent dir */
4684 #if FS_STATS_DETAILED
4685     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4686                              parentptr->disk.linkCount+1, client->InSameNetwork);
4687 #else
4688     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
4689                              parentptr->disk.linkCount+1);
4690 #endif /* FS_STATS_DETAILED */
4691
4692     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
4693     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
4694                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
4695     assert(parentwhentargetnotdir == 0);
4696     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
4697
4698     /* update the status for the target vnode */
4699     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
4700                              parentptr, volptr, (afs_size_t)0);
4701
4702     /* Actually create the New directory in the directory package */ 
4703     SetDirHandle(&dir, targetptr);
4704     assert(!(MakeDir(&dir, OutFid, DirFid)));
4705     DFlush();
4706     VN_SET_LEN(targetptr, (afs_size_t) Length(&dir));
4707
4708     /* set up return status */
4709     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
4710     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4711
4712     /* convert the write lock to a read lock before breaking callbacks */
4713     VVnodeWriteToRead(&errorCode, parentptr);
4714     assert(!errorCode || errorCode == VSALVAGE);
4715
4716     /* break call back on DirFid */
4717     BreakCallBack(client->host, DirFid, 0);
4718
4719     /* Return a callback promise to caller */
4720     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
4721
4722 Bad_MakeDir: 
4723     /* Write the all modified vnodes (parent, new files) and volume back */
4724     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4725     FidZap(&dir);
4726     FidZap(&parentdir);
4727     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
4728     return errorCode;
4729
4730 } /*SAFSS_MakeDir*/
4731
4732
4733 afs_int32 SRXAFS_MakeDir (struct rx_call *acall,
4734                           struct AFSFid *DirFid,
4735                           char *Name,
4736                           struct AFSStoreStatus *InStatus,
4737                           struct AFSFid *OutFid,
4738                           struct AFSFetchStatus *OutFidStatus,
4739                           struct AFSFetchStatus *OutDirStatus,
4740                           struct AFSCallBack *CallBack,
4741                           struct AFSVolSync *Sync)
4742 {
4743     afs_int32 code;
4744     struct rx_connection *tcon;
4745 #if FS_STATS_DETAILED
4746     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4747     struct timeval opStartTime,
4748                    opStopTime;              /* Start/stop times for RPC op*/
4749     struct timeval elapsedTime;             /* Transfer time */
4750
4751     /*
4752      * Set our stats pointer, remember when the RPC operation started, and
4753      * tally the operation.
4754      */
4755     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
4756     FS_LOCK
4757     (opP->numOps)++;
4758     FS_UNLOCK
4759     TM_GetTimeOfDay(&opStartTime, 0);
4760 #endif /* FS_STATS_DETAILED */
4761     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4762         goto Bad_MakeDir;
4763
4764     code = SAFSS_MakeDir (acall, DirFid, Name, InStatus, OutFid,
4765                          OutFidStatus, OutDirStatus, CallBack, Sync);
4766     
4767 Bad_MakeDir:
4768     code = CallPostamble(tcon, code);
4769
4770 #if FS_STATS_DETAILED
4771     TM_GetTimeOfDay(&opStopTime, 0);
4772     if (code == 0) {
4773       FS_LOCK
4774       (opP->numSuccesses)++;
4775       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4776       fs_stats_AddTo((opP->sumTime), elapsedTime);
4777       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4778       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4779         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4780       }
4781       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4782         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4783       }
4784       FS_UNLOCK
4785     }
4786
4787 #endif /* FS_STATS_DETAILED */
4788
4789     osi_auditU (acall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4790     return code;
4791
4792 } /*SRXAFS_MakeDir*/
4793
4794
4795 /*
4796  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
4797  * merged into it when possible.
4798  */
4799 static afs_int32
4800 SAFSS_RemoveDir (struct rx_call *acall,
4801                  struct AFSFid *DirFid,
4802                  char *Name,
4803                  struct AFSFetchStatus *OutDirStatus,
4804                  struct AFSVolSync *Sync)
4805
4806 {
4807     Vnode * parentptr = 0;              /* vnode of input Directory */
4808     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4809     Vnode * targetptr = 0;              /* file to be deleted */
4810     AFSFid fileFid;                     /* area for Fid from the directory */
4811     int     errorCode = 0;              /* error code */
4812     DirHandle dir;                      /* Handle for dir package I/O */
4813     Volume * volptr = 0;                /* pointer to the volume header */
4814     struct client * client;             /* pointer to client structure */
4815     afs_int32 rights, anyrights;                /* rights for this and any user */
4816     Vnode debugvnode1, debugvnode2;
4817     struct client *t_client;            /* tmp ptr to client data */
4818     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4819     struct rx_connection *tcon = rx_ConnectionOf(acall);
4820
4821     FidZero(&dir);
4822
4823     /* Get ptr to client data for user Id for logging */
4824     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4825     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4826     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
4827             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
4828             inet_ntoa(logHostAddr), t_client->ViceId));
4829     FS_LOCK
4830     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
4831     FS_UNLOCK
4832     /*
4833      * Get the vnode and volume for the parent dir along with the caller's
4834      * rights to it
4835      */
4836     if ((errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
4837                                      MustBeDIR, &parentwhentargetnotdir,
4838                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4839         goto Bad_RemoveDir;
4840     }
4841     debugvnode1 = *parentptr;
4842
4843     /* set volume synchronization information */
4844     SetVolumeSync(Sync, volptr);
4845
4846     /* Does the caller has delete (&write) access to the parent dir? */
4847     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
4848         goto Bad_RemoveDir;
4849     }
4850
4851     debugvnode2 = *parentptr;
4852     /* Do the actual delete of the desired (empty) directory, Name */
4853     if ((errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
4854                                  Name, MustBeDIR))) {
4855         goto Bad_RemoveDir;
4856     }
4857
4858     /* Update the status for the parent dir; link count is also adjusted */
4859 #if FS_STATS_DETAILED
4860     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4861                              parentptr->disk.linkCount-1, client->InSameNetwork);
4862 #else
4863     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
4864                              parentptr->disk.linkCount-1);
4865 #endif /* FS_STATS_DETAILED */
4866
4867     /* Return to the caller the updated parent dir status */
4868     GetStatus(parentptr, OutDirStatus, rights, anyrights, NULL);
4869
4870     /*
4871      * Note: it is not necessary to break the callback on fileFid, since
4872      * refcount is now 0, so no one should be able to refer to the dir
4873      * any longer
4874      */
4875     DeleteFileCallBacks(&fileFid);
4876
4877     /* convert the write lock to a read lock before breaking callbacks */
4878     VVnodeWriteToRead(&errorCode, parentptr);
4879     assert(!errorCode || errorCode == VSALVAGE);
4880
4881     /* break call back on DirFid and fileFid */
4882     BreakCallBack(client->host, DirFid, 0);
4883
4884 Bad_RemoveDir: 
4885     /* Write the all modified vnodes (parent, new files) and volume back */
4886     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
4887     FidZap(&dir);
4888     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
4889     return errorCode;
4890
4891 } /*SAFSS_RemoveDir*/
4892
4893
4894 afs_int32 SRXAFS_RemoveDir (struct rx_call *acall,
4895                             struct AFSFid *DirFid,
4896                             char *Name,
4897                             struct AFSFetchStatus *OutDirStatus,
4898                             struct AFSVolSync *Sync)
4899 {
4900     afs_int32 code;
4901     struct rx_connection *tcon;
4902 #if FS_STATS_DETAILED
4903     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
4904     struct timeval opStartTime,
4905                    opStopTime;              /* Start/stop times for RPC op*/
4906     struct timeval elapsedTime;             /* Transfer time */
4907
4908     /*
4909      * Set our stats pointer, remember when the RPC operation started, and
4910      * tally the operation.
4911      */
4912     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
4913     FS_LOCK
4914     (opP->numOps)++;
4915     FS_UNLOCK
4916     TM_GetTimeOfDay(&opStartTime, 0);
4917 #endif /* FS_STATS_DETAILED */
4918
4919     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
4920         goto Bad_RemoveDir;
4921
4922     code = SAFSS_RemoveDir (acall, DirFid, Name, OutDirStatus, Sync);
4923     
4924 Bad_RemoveDir:
4925     code = CallPostamble(tcon, code);
4926
4927 #if FS_STATS_DETAILED
4928     TM_GetTimeOfDay(&opStopTime, 0);
4929     if (code == 0) {
4930       FS_LOCK
4931       (opP->numSuccesses)++;
4932       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
4933       fs_stats_AddTo((opP->sumTime), elapsedTime);
4934       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
4935       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
4936         fs_stats_TimeAssign((opP->minTime), elapsedTime);
4937       }
4938       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
4939         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
4940       }
4941       FS_UNLOCK
4942     }
4943
4944 #endif /* FS_STATS_DETAILED */
4945
4946     osi_auditU (acall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
4947     return code;
4948
4949 } /*SRXAFS_RemoveDir*/
4950
4951
4952 /*
4953  * This routine is called exclusively by SRXAFS_SetLock(), and should be
4954  * merged into it when possible.
4955  */
4956 static afs_int32
4957 SAFSS_SetLock (struct rx_call *acall,
4958                struct AFSFid *Fid,
4959                ViceLockType type,
4960                struct AFSVolSync *Sync)
4961 {
4962     Vnode * targetptr = 0;              /* vnode of input file */
4963     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
4964     int     errorCode = 0;              /* error code */
4965     Volume * volptr = 0;                /* pointer to the volume header */
4966     struct client * client;             /* pointer to client structure */
4967     afs_int32 rights, anyrights;                /* rights for this and any user */
4968     struct client *t_client;            /* tmp ptr to client data */
4969     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
4970     static char * locktype[2] = {"LockRead","LockWrite"};
4971     struct rx_connection *tcon = rx_ConnectionOf(acall);
4972
4973     if (type != LockRead && type != LockWrite) {
4974         errorCode = EINVAL;
4975         goto Bad_SetLock;
4976     }
4977     /* Get ptr to client data for user Id for logging */
4978     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
4979     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
4980     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
4981             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
4982             inet_ntoa(logHostAddr), t_client->ViceId));
4983     FS_LOCK
4984     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
4985     FS_UNLOCK
4986
4987     /*
4988      * Get the vnode and volume for the desired file along with the caller's
4989      * rights to it
4990      */
4991     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
4992                                      DONTCHECK, &parentwhentargetnotdir,
4993                                      &client, WRITE_LOCK, &rights, &anyrights))) {
4994         goto Bad_SetLock;
4995     }
4996
4997     /* set volume synchronization information */
4998     SetVolumeSync(Sync, volptr);
4999
5000     /* Handle the particular type of set locking, type */
5001     errorCode = HandleLocking(targetptr, rights, type);
5002
5003 Bad_SetLock: 
5004     /* Write the all modified vnodes (parent, new files) and volume back */
5005     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5006
5007     if ((errorCode == VREADONLY) && (type == LockRead))
5008        errorCode = 0;  /* allow read locks on RO volumes without saving state */
5009
5010     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
5011     return(errorCode);
5012
5013 }  /*SAFSS_SetLock*/
5014
5015
5016 afs_int32 SRXAFS_OldSetLock(struct rx_call *acall,
5017                             struct AFSFid *Fid,
5018                             ViceLockType type,
5019                             struct AFSVolSync *Sync)
5020 {
5021     return SRXAFS_SetLock(acall, Fid, type, Sync);
5022
5023 } /*SRXAFS_OldSetLock*/
5024
5025
5026 afs_int32 SRXAFS_SetLock (struct rx_call *acall,
5027                           struct AFSFid *Fid,
5028                           ViceLockType type,
5029                           struct AFSVolSync *Sync)
5030 {
5031     afs_int32 code;
5032     struct rx_connection *tcon;
5033 #if FS_STATS_DETAILED
5034     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5035     struct timeval opStartTime,
5036                    opStopTime;              /* Start/stop times for RPC op*/
5037     struct timeval elapsedTime;             /* Transfer time */
5038
5039     /*
5040      * Set our stats pointer, remember when the RPC operation started, and
5041      * tally the operation.
5042      */
5043     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
5044     FS_LOCK
5045     (opP->numOps)++;
5046     FS_UNLOCK
5047     TM_GetTimeOfDay(&opStartTime, 0);
5048 #endif /* FS_STATS_DETAILED */
5049
5050     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5051         goto Bad_SetLock;
5052
5053     code = SAFSS_SetLock (acall, Fid, type, Sync);
5054     
5055 Bad_SetLock:
5056     code = CallPostamble(tcon, code);
5057
5058 #if FS_STATS_DETAILED
5059     TM_GetTimeOfDay(&opStopTime, 0); 
5060     if (code == 0) {
5061       FS_LOCK
5062       (opP->numSuccesses)++;
5063       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5064       fs_stats_AddTo((opP->sumTime), elapsedTime);
5065       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5066       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5067         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5068       }
5069       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5070         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5071       }
5072       FS_UNLOCK
5073     }
5074 #endif /* FS_STATS_DETAILED */
5075
5076     osi_auditU (acall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
5077     return code;
5078
5079 } /*SRXAFS_SetLock*/
5080
5081
5082 /*
5083  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
5084  * merged into it when possible.
5085  */
5086 static afs_int32 
5087 SAFSS_ExtendLock (struct rx_call *acall,
5088                   struct AFSFid *Fid,
5089                   struct AFSVolSync *Sync)
5090
5091 {
5092     Vnode * targetptr = 0;              /* vnode of input file */
5093     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5094     int     errorCode = 0;              /* error code */
5095     Volume * volptr = 0;                /* pointer to the volume header */
5096     struct client * client;             /* pointer to client structure */
5097     afs_int32 rights, anyrights;                /* rights for this and any user */
5098     struct client *t_client;            /* tmp ptr to client data */
5099     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5100     struct rx_connection *tcon = rx_ConnectionOf(acall);
5101
5102     /* Get ptr to client data for user Id for logging */
5103     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5104     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5105     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
5106                Fid->Volume, Fid->Vnode, Fid->Unique, 
5107                inet_ntoa(logHostAddr), t_client->ViceId));
5108     FS_LOCK
5109     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
5110     FS_UNLOCK
5111     /*
5112      * Get the vnode and volume for the desired file along with the caller's
5113      * rights to it
5114      */
5115     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5116                                      DONTCHECK, &parentwhentargetnotdir,
5117                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5118         goto Bad_ExtendLock;
5119     }
5120
5121     /* set volume synchronization information */
5122     SetVolumeSync(Sync, volptr);
5123
5124     /* Handle the actual lock extension */
5125     errorCode = HandleLocking(targetptr, rights, LockExtend);
5126
5127 Bad_ExtendLock: 
5128     /* Put back file's vnode and volume */
5129     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5130
5131     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5132        errorCode = 0;              /* under our generous policy re RO vols */
5133
5134     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
5135     return(errorCode);
5136
5137 } /*SAFSS_ExtendLock*/
5138
5139
5140 afs_int32 SRXAFS_OldExtendLock (struct rx_call *acall,
5141                                 struct AFSFid *Fid,
5142                                 struct AFSVolSync *Sync)
5143 {
5144     return SRXAFS_ExtendLock(acall, Fid, Sync);
5145
5146 } /*SRXAFS_OldExtendLock*/
5147
5148
5149 afs_int32 SRXAFS_ExtendLock (struct rx_call *acall,
5150                              struct AFSFid *Fid,
5151                              struct AFSVolSync *Sync)
5152 {
5153     afs_int32 code;
5154     struct rx_connection *tcon;
5155 #if FS_STATS_DETAILED
5156     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5157     struct timeval opStartTime,
5158                    opStopTime;              /* Start/stop times for RPC op*/
5159     struct timeval elapsedTime;             /* Transfer time */
5160
5161     /*
5162      * Set our stats pointer, remember when the RPC operation started, and
5163      * tally the operation.
5164      */
5165     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_EXTENDLOCK]);
5166     FS_LOCK
5167     (opP->numOps)++;
5168     FS_UNLOCK
5169     TM_GetTimeOfDay(&opStartTime, 0);
5170 #endif /* FS_STATS_DETAILED */
5171
5172     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5173         goto Bad_ExtendLock;
5174
5175     code = SAFSS_ExtendLock (acall, Fid, Sync);
5176
5177 Bad_ExtendLock:
5178     code = CallPostamble(tcon, code);
5179
5180 #if FS_STATS_DETAILED
5181     TM_GetTimeOfDay(&opStopTime, 0);
5182     if (code == 0) {
5183       FS_LOCK
5184       (opP->numSuccesses)++;
5185       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5186       fs_stats_AddTo((opP->sumTime), elapsedTime);
5187       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5188       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5189         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5190       }
5191       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5192         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5193       }
5194       FS_UNLOCK
5195     }
5196
5197 #endif /* FS_STATS_DETAILED */
5198
5199     osi_auditU (acall, ExtendLockEvent, code, AUD_FID, Fid , AUD_END);
5200     return code;
5201
5202 } /*SRXAFS_ExtendLock*/
5203
5204
5205 /*
5206  * This routine is called exclusively by SRXAFS_ReleaseLock(), and should be
5207  * merged into it when possible.
5208  */
5209 static afs_int32 
5210 SAFSS_ReleaseLock (struct rx_call *acall,
5211                    struct AFSFid *Fid,
5212                    struct AFSVolSync *Sync)
5213
5214 {
5215     Vnode * targetptr = 0;              /* vnode of input file */
5216     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
5217     int     errorCode = 0;              /* error code */
5218     Volume * volptr = 0;                /* pointer to the volume header */
5219     struct client * client;             /* pointer to client structure */
5220     afs_int32 rights, anyrights;                /* rights for this and any user */
5221     struct client *t_client;            /* tmp ptr to client data */
5222     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
5223     struct rx_connection *tcon = rx_ConnectionOf(acall);
5224
5225     /* Get ptr to client data for user Id for logging */
5226     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
5227     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
5228     ViceLog(1,("SAFS_ReleaseLock Fid = %u.%d.%d, Host %s, Id %d\n",
5229             Fid->Volume, Fid->Vnode, Fid->Unique,
5230             inet_ntoa(logHostAddr), t_client->ViceId));
5231     FS_LOCK
5232     AFSCallStats.ReleaseLock++, AFSCallStats.TotalCalls++;
5233     FS_UNLOCK
5234     /*
5235      * Get the vnode and volume for the desired file along with the caller's
5236      * rights to it
5237      */
5238     if ((errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
5239                                      DONTCHECK, &parentwhentargetnotdir,
5240                                      &client, WRITE_LOCK, &rights, &anyrights))) {
5241         goto Bad_ReleaseLock;
5242     }
5243
5244     /* set volume synchronization information */
5245     SetVolumeSync(Sync, volptr);
5246
5247     /* Handle the actual lock release */
5248     if ((errorCode = HandleLocking(targetptr, rights, LockRelease)))
5249         goto Bad_ReleaseLock;
5250
5251     /* if no more locks left, a callback would be triggered here */
5252     if (targetptr->disk.lock.lockCount <= 0) {
5253         /* convert the write lock to a read lock before breaking callbacks */
5254         VVnodeWriteToRead(&errorCode, targetptr);
5255         assert(!errorCode || errorCode == VSALVAGE);
5256         BreakCallBack(client->host, Fid, 0);
5257     }
5258
5259 Bad_ReleaseLock: 
5260     /* Put back file's vnode and volume */
5261     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
5262
5263     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
5264        errorCode = 0;              /* under our generous policy re RO vols */
5265
5266     ViceLog(2,("SAFS_ReleaseLock returns %d\n", errorCode));
5267     return(errorCode);
5268
5269 } /*SAFSS_ReleaseLock*/
5270
5271
5272 afs_int32 SRXAFS_OldReleaseLock (struct rx_call *acall,
5273                                  struct AFSFid *Fid,
5274                                  struct AFSVolSync *Sync)
5275 {
5276     return SRXAFS_ReleaseLock(acall, Fid, Sync);
5277
5278 } /*SRXAFS_OldReleaseLock*/
5279
5280
5281 afs_int32 SRXAFS_ReleaseLock (struct rx_call *acall,
5282                               struct AFSFid *Fid,
5283                               struct AFSVolSync *Sync)
5284 {
5285     afs_int32 code;
5286     struct rx_connection *tcon;
5287 #if FS_STATS_DETAILED
5288     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5289     struct timeval opStartTime,
5290                    opStopTime;              /* Start/stop times for RPC op*/
5291     struct timeval elapsedTime;             /* Transfer time */
5292
5293     /*
5294      * Set our stats pointer, remember when the RPC operation started, and
5295      * tally the operation.
5296      */
5297     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RELEASELOCK]);
5298     FS_LOCK
5299     (opP->numOps)++;
5300     FS_UNLOCK
5301     TM_GetTimeOfDay(&opStartTime, 0);
5302 #endif /* FS_STATS_DETAILED */
5303
5304     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
5305         goto Bad_ReleaseLock;
5306
5307     code = SAFSS_ReleaseLock (acall, Fid, Sync);
5308     
5309 Bad_ReleaseLock:
5310     code = CallPostamble(tcon, code);
5311
5312 #if FS_STATS_DETAILED
5313     TM_GetTimeOfDay(&opStopTime, 0);
5314     if (code == 0) {
5315       FS_LOCK
5316       (opP->numSuccesses)++;
5317       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5318       fs_stats_AddTo((opP->sumTime), elapsedTime);
5319       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5320       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5321         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5322       }
5323       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5324         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5325       }
5326       FS_UNLOCK
5327     }
5328
5329 #endif /* FS_STATS_DETAILED */
5330
5331     osi_auditU (acall, ReleaseLockEvent, code, AUD_FID, Fid , AUD_END);
5332     return code;
5333
5334 } /*SRXAFS_ReleaseLock*/
5335
5336
5337 void SetSystemStats(struct AFSStatistics *stats)
5338 {
5339   /* Fix this sometime soon.. */
5340   /* Because hey, it's not like we have a network monitoring protocol... */
5341     struct      timeval time;
5342
5343     /* this works on all system types */
5344     TM_GetTimeOfDay(&time, 0);
5345     stats->CurrentTime = time.tv_sec;
5346 } /*SetSystemStats*/
5347
5348 void SetAFSStats(struct AFSStatistics *stats)
5349 {
5350     extern afs_int32 StartTime, CurrentConnections;
5351     int seconds;
5352
5353     FS_LOCK
5354     stats->CurrentMsgNumber = 0;
5355     stats->OldestMsgNumber = 0;
5356     stats->StartTime = StartTime;
5357     stats->CurrentConnections = CurrentConnections;
5358     stats->TotalAFSCalls = AFSCallStats.TotalCalls;
5359     stats->TotalFetchs = AFSCallStats.FetchData+AFSCallStats.FetchACL+AFSCallStats.FetchStatus;
5360     stats->FetchDatas = AFSCallStats.FetchData;
5361     stats->FetchedBytes = AFSCallStats.TotalFetchedBytes;
5362     seconds = AFSCallStats.AccumFetchTime/1000;
5363     if (seconds <= 0) seconds = 1;
5364     stats->FetchDataRate = AFSCallStats.TotalFetchedBytes/seconds;
5365     stats->TotalStores = AFSCallStats.StoreData+AFSCallStats.StoreACL+AFSCallStats.StoreStatus;
5366     stats->StoreDatas = AFSCallStats.StoreData;
5367     stats->StoredBytes = AFSCallStats.TotalStoredBytes;
5368     seconds = AFSCallStats.AccumStoreTime/1000;
5369     if (seconds <= 0) seconds = 1;
5370     stats->StoreDataRate = AFSCallStats.TotalStoredBytes/seconds;
5371 #ifdef AFS_NT40_ENV
5372     stats->ProcessSize = -1; /* TODO: */
5373 #else
5374     stats->ProcessSize = (afs_int32)((long) sbrk(0) >> 10);
5375 #endif
5376     FS_UNLOCK
5377     h_GetWorkStats((int *)&(stats->WorkStations),(int *)&(stats->ActiveWorkStations),
5378             (int *)0, (afs_int32)(FT_ApproxTime())-(15*60));
5379
5380 } /*SetAFSStats*/
5381
5382 /* Get disk related information from all AFS partitions. */
5383
5384 void SetVolumeStats(struct AFSStatistics *stats)
5385 {
5386     struct DiskPartition * part;
5387     int i = 0;
5388
5389     for (part = DiskPartitionList; part && i < AFS_MSTATDISKS; part = part->next) {
5390         stats->Disks[i].TotalBlocks = part->totalUsable;
5391         stats->Disks[i].BlocksAvailable = part->free;
5392         memset(stats->Disks[i].Name, 0, AFS_DISKNAMESIZE);
5393         strncpy(stats->Disks[i].Name, part->name, AFS_DISKNAMESIZE);
5394         i++;
5395     }
5396     while (i < AFS_MSTATDISKS) {
5397         stats->Disks[i].TotalBlocks = -1;
5398         i++;
5399     }
5400 } /*SetVolumeStats*/
5401
5402 afs_int32 SRXAFS_GetStatistics (struct rx_call *acall,
5403                                 struct ViceStatistics *Statistics)
5404 {
5405     afs_int32 code;
5406     struct rx_connection *tcon;
5407 #if FS_STATS_DETAILED
5408     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5409     struct timeval opStartTime,
5410                    opStopTime;              /* Start/stop times for RPC op*/
5411     struct timeval elapsedTime;             /* Transfer time */
5412
5413     /*
5414      * Set our stats pointer, remember when the RPC operation started, and
5415      * tally the operation.
5416      */
5417     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETSTATISTICS]);
5418     FS_LOCK
5419     (opP->numOps)++;
5420     FS_UNLOCK
5421     TM_GetTimeOfDay(&opStartTime, 0);
5422 #endif /* FS_STATS_DETAILED */
5423
5424     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
5425         goto Bad_GetStatistics;
5426
5427     ViceLog(1, ("SAFS_GetStatistics Received\n"));
5428     FS_LOCK
5429     AFSCallStats.GetStatistics++, AFSCallStats.TotalCalls++;
5430     FS_UNLOCK
5431     memset(Statistics, 0, sizeof(*Statistics));
5432     SetAFSStats((struct AFSStatistics *)Statistics);
5433     SetVolumeStats((struct AFSStatistics *)Statistics);
5434     SetSystemStats((struct AFSStatistics *)Statistics);
5435     
5436 Bad_GetStatistics:
5437     code = CallPostamble(tcon, code);
5438
5439 #if FS_STATS_DETAILED
5440     TM_GetTimeOfDay(&opStopTime, 0);
5441     if (code == 0) {
5442       FS_LOCK
5443       (opP->numSuccesses)++;
5444       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5445       fs_stats_AddTo((opP->sumTime), elapsedTime);
5446       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5447       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5448         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5449       }
5450       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5451         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5452       }
5453       FS_UNLOCK
5454     }
5455 #endif /* FS_STATS_DETAILED */
5456
5457     return code;
5458
5459 } /*SRXAFS_GetStatistics*/
5460
5461
5462 /*------------------------------------------------------------------------
5463  * EXPORTED SRXAFS_XStatsVersion
5464  *
5465  * Description:
5466  *      Routine called by the server-side RPC interface to implement
5467  *      pulling out the xstat version number for the File Server.
5468  *
5469  * Arguments:
5470  *      a_versionP : Ptr to the version number variable to set.
5471  *
5472  * Returns:
5473  *      0 (always)
5474  *
5475  * Environment:
5476  *      Nothing interesting.
5477  *
5478  * Side Effects:
5479  *      As advertised.
5480  *------------------------------------------------------------------------*/
5481
5482 afs_int32 SRXAFS_XStatsVersion(struct rx_call *a_call, afs_int32 *a_versionP)
5483 { /*SRXAFS_XStatsVersion*/
5484
5485 #if FS_STATS_DETAILED
5486     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5487     struct timeval opStartTime,
5488                    opStopTime;              /* Start/stop times for RPC op*/
5489     struct timeval elapsedTime;             /* Transfer time */
5490
5491     /*
5492      * Set our stats pointer, remember when the RPC operation started, and
5493      * tally the operation.
5494      */
5495     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_XSTATSVERSION]);
5496     FS_LOCK
5497     (opP->numOps)++;
5498     FS_UNLOCK
5499     TM_GetTimeOfDay(&opStartTime, 0);
5500 #endif /* FS_STATS_DETAILED */
5501
5502     *a_versionP = AFS_XSTAT_VERSION;
5503
5504 #if FS_STATS_DETAILED
5505     TM_GetTimeOfDay(&opStopTime, 0);
5506     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5507     fs_stats_AddTo((opP->sumTime), elapsedTime);
5508     fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5509     if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5510         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5511     }
5512     if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5513         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5514     }
5515     FS_LOCK
5516     (opP->numSuccesses)++;
5517     FS_UNLOCK
5518 #endif /* FS_STATS_DETAILED */
5519
5520     return(0);
5521
5522 }  /*SRXAFS_XStatsVersion*/
5523
5524
5525 /*------------------------------------------------------------------------
5526  * PRIVATE FillPerfValues
5527  *
5528  * Description:
5529  *      Routine called to fill a regular performance data structure.
5530  *
5531  * Arguments:
5532  *      a_perfP : Ptr to perf structure to fill
5533  *
5534  * Returns:
5535  *      Nothing.
5536  *
5537  * Environment:
5538  *      Various collections need this info, so the guts were put in
5539  *      this separate routine.
5540  *
5541  * Side Effects:
5542  *      As advertised.
5543  *------------------------------------------------------------------------*/
5544
5545 static void FillPerfValues(struct afs_PerfStats *a_perfP)
5546 { /*FillPerfValues*/
5547
5548     int dir_Buffers;            /*# buffers in use by dir package*/
5549     int dir_Calls;              /*# read calls in dir package*/
5550     int dir_IOs;                /*# I/O ops in dir package*/
5551
5552     /*
5553      * Vnode cache section.
5554      */
5555     a_perfP->vcache_L_Entries = VnodeClassInfo[vLarge].cacheSize;
5556     a_perfP->vcache_L_Allocs = VnodeClassInfo[vLarge].allocs;
5557     a_perfP->vcache_L_Gets = VnodeClassInfo[vLarge].gets;
5558     a_perfP->vcache_L_Reads = VnodeClassInfo[vLarge].reads;
5559     a_perfP->vcache_L_Writes = VnodeClassInfo[vLarge].writes;
5560     a_perfP->vcache_S_Entries = VnodeClassInfo[vSmall].cacheSize;
5561     a_perfP->vcache_S_Allocs = VnodeClassInfo[vSmall].allocs;
5562     a_perfP->vcache_S_Gets = VnodeClassInfo[vSmall].gets;
5563     a_perfP->vcache_S_Reads = VnodeClassInfo[vSmall].reads;
5564     a_perfP->vcache_S_Writes = VnodeClassInfo[vSmall].writes;
5565     a_perfP->vcache_H_Entries = VolumeCacheSize;
5566     a_perfP->vcache_H_Gets = VolumeGets;
5567     a_perfP->vcache_H_Replacements = VolumeReplacements;
5568     
5569     /*
5570      * Directory section.
5571      */
5572     DStat(&dir_Buffers, &dir_Calls, &dir_IOs);
5573     a_perfP->dir_Buffers = (afs_int32) dir_Buffers;
5574     a_perfP->dir_Calls = (afs_int32 )dir_Calls;
5575     a_perfP->dir_IOs = (afs_int32) dir_IOs;
5576     
5577     /*
5578      * Rx section.
5579      */
5580     a_perfP->rx_packetRequests =
5581         (afs_int32) rx_stats.packetRequests;
5582     a_perfP->rx_noPackets_RcvClass =
5583         (afs_int32) rx_stats.receivePktAllocFailures;
5584     a_perfP->rx_noPackets_SendClass =
5585         (afs_int32) rx_stats.sendPktAllocFailures;
5586     a_perfP->rx_noPackets_SpecialClass =
5587         (afs_int32) rx_stats.specialPktAllocFailures;
5588     a_perfP->rx_socketGreedy =
5589         (afs_int32) rx_stats.socketGreedy;
5590     a_perfP->rx_bogusPacketOnRead =
5591         (afs_int32) rx_stats.bogusPacketOnRead;
5592     a_perfP->rx_bogusHost =
5593         (afs_int32) rx_stats.bogusHost;
5594     a_perfP->rx_noPacketOnRead =
5595         (afs_int32) rx_stats.noPacketOnRead;
5596     a_perfP->rx_noPacketBuffersOnRead =
5597         (afs_int32) rx_stats.noPacketBuffersOnRead;
5598     a_perfP->rx_selects =
5599         (afs_int32) rx_stats.selects;
5600     a_perfP->rx_sendSelects =
5601         (afs_int32) rx_stats.sendSelects;
5602     a_perfP->rx_packetsRead_RcvClass =
5603         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_RECEIVE];
5604     a_perfP->rx_packetsRead_SendClass =
5605         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SEND];
5606     a_perfP->rx_packetsRead_SpecialClass =
5607         (afs_int32) rx_stats.packetsRead[RX_PACKET_CLASS_SPECIAL];
5608     a_perfP->rx_dataPacketsRead =
5609         (afs_int32) rx_stats.dataPacketsRead;
5610     a_perfP->rx_ackPacketsRead =
5611         (afs_int32) rx_stats.ackPacketsRead;
5612     a_perfP->rx_dupPacketsRead =
5613         (afs_int32) rx_stats.dupPacketsRead;
5614     a_perfP->rx_spuriousPacketsRead =
5615         (afs_int32) rx_stats.spuriousPacketsRead;
5616     a_perfP->rx_packetsSent_RcvClass =
5617         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_RECEIVE];
5618     a_perfP->rx_packetsSent_SendClass =
5619         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SEND];
5620     a_perfP->rx_packetsSent_SpecialClass =
5621         (afs_int32) rx_stats.packetsSent[RX_PACKET_CLASS_SPECIAL];
5622     a_perfP->rx_ackPacketsSent =
5623         (afs_int32) rx_stats.ackPacketsSent;
5624     a_perfP->rx_pingPacketsSent =
5625         (afs_int32) rx_stats.pingPacketsSent;
5626     a_perfP->rx_abortPacketsSent =
5627         (afs_int32) rx_stats.abortPacketsSent;
5628     a_perfP->rx_busyPacketsSent =
5629         (afs_int32) rx_stats.busyPacketsSent;
5630     a_perfP->rx_dataPacketsSent =
5631         (afs_int32) rx_stats.dataPacketsSent;
5632     a_perfP->rx_dataPacketsReSent =
5633         (afs_int32) rx_stats.dataPacketsReSent;
5634     a_perfP->rx_dataPacketsPushed =
5635         (afs_int32) rx_stats.dataPacketsPushed;
5636     a_perfP->rx_ignoreAckedPacket =
5637         (afs_int32) rx_stats.ignoreAckedPacket;
5638     a_perfP->rx_totalRtt_Sec =
5639         (afs_int32) rx_stats.totalRtt.sec;
5640     a_perfP->rx_totalRtt_Usec =
5641         (afs_int32) rx_stats.totalRtt.usec;
5642     a_perfP->rx_minRtt_Sec =
5643         (afs_int32) rx_stats.minRtt.sec;
5644     a_perfP->rx_minRtt_Usec =
5645         (afs_int32) rx_stats.minRtt.usec;
5646     a_perfP->rx_maxRtt_Sec =
5647         (afs_int32) rx_stats.maxRtt.sec;
5648     a_perfP->rx_maxRtt_Usec =
5649         (afs_int32) rx_stats.maxRtt.usec;
5650     a_perfP->rx_nRttSamples =
5651         (afs_int32) rx_stats.nRttSamples;
5652     a_perfP->rx_nServerConns =
5653         (afs_int32) rx_stats.nServerConns;
5654     a_perfP->rx_nClientConns =
5655         (afs_int32) rx_stats.nClientConns;
5656     a_perfP->rx_nPeerStructs =
5657         (afs_int32) rx_stats.nPeerStructs;
5658     a_perfP->rx_nCallStructs =
5659         (afs_int32) rx_stats.nCallStructs;
5660     a_perfP->rx_nFreeCallStructs =
5661         (afs_int32) rx_stats.nFreeCallStructs;
5662     
5663     a_perfP->host_NumHostEntries = HTs;
5664     a_perfP->host_HostBlocks = HTBlocks;
5665     h_GetHostNetStats(&(a_perfP->host_NonDeletedHosts),
5666                       &(a_perfP->host_HostsInSameNetOrSubnet),
5667                       &(a_perfP->host_HostsInDiffSubnet),
5668                       &(a_perfP->host_HostsInDiffNetwork));
5669     a_perfP->host_NumClients = CEs;
5670     a_perfP->host_ClientBlocks = CEBlocks;
5671     
5672     a_perfP->sysname_ID = afs_perfstats.sysname_ID;
5673
5674 } /*FillPerfValues*/
5675
5676
5677 /*------------------------------------------------------------------------
5678  * EXPORTED SRXAFS_GetXStats
5679  *
5680  * Description:
5681  *      Routine called by the server-side callback RPC interface to
5682  *      implement getting the given data collection from the extended
5683  *      File Server statistics.
5684  *
5685  * Arguments:
5686  *      a_call              : Ptr to Rx call on which this request came in.
5687  *      a_clientVersionNum  : Client version number.
5688  *      a_opCode            : Desired operation.
5689  *      a_serverVersionNumP : Ptr to version number to set.
5690  *      a_timeP             : Ptr to time value (seconds) to set.
5691  *      a_dataP             : Ptr to variable array structure to return
5692  *                            stuff in.
5693  *
5694  * Returns:
5695  *      0 (always).
5696  *
5697  * Environment:
5698  *      Nothing interesting.
5699  *
5700  * Side Effects:
5701  *      As advertised.
5702  *------------------------------------------------------------------------*/
5703
5704 afs_int32 SRXAFS_GetXStats(struct rx_call *a_call,
5705                            afs_int32 a_clientVersionNum,
5706                            afs_int32 a_collectionNumber,
5707                            afs_int32 *a_srvVersionNumP,
5708                            afs_int32 *a_timeP,
5709                            AFS_CollData *a_dataP)
5710 { /*SRXAFS_GetXStats*/
5711
5712     register int code;          /*Return value*/
5713     afs_int32 *dataBuffP;               /*Ptr to data to be returned*/
5714     afs_int32 dataBytes;                /*Bytes in data buffer*/
5715 #if FS_STATS_DETAILED
5716     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5717     struct timeval opStartTime,
5718                    opStopTime;              /* Start/stop times for RPC op*/
5719     struct timeval elapsedTime;             /* Transfer time */
5720
5721     /*
5722      * Set our stats pointer, remember when the RPC operation started, and
5723      * tally the operation.
5724      */
5725     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETXSTATS]);
5726     FS_LOCK
5727     (opP->numOps)++;
5728     FS_UNLOCK
5729     TM_GetTimeOfDay(&opStartTime, 0);
5730 #endif /* FS_STATS_DETAILED */
5731
5732     /*
5733      * Record the time of day and the server version number.
5734      */
5735     *a_srvVersionNumP = AFS_XSTAT_VERSION;
5736     *a_timeP = FT_ApproxTime();
5737
5738     /*
5739      * Stuff the appropriate data in there (assume victory)
5740      */
5741     code = 0;
5742
5743     ViceLog(1, ("Received GetXStats call for collection %d\n",  a_collectionNumber));
5744
5745 #if 0
5746     /*
5747      * We're not keeping stats, so just return successfully with
5748      * no data.
5749      */
5750     a_dataP->AFS_CollData_len = 0;
5751     a_dataP->AFS_CollData_val = NULL;
5752 #endif /* 0 */
5753
5754     switch(a_collectionNumber) {
5755       case AFS_XSTATSCOLL_CALL_INFO:
5756         /*
5757          * Pass back all the call-count-related data.
5758          *
5759          * >>> We are forced to allocate a separate area in which to
5760          * >>> put this stuff in by the RPC stub generator, since it
5761          * >>> will be freed at the tail end of the server stub code.
5762          */
5763 #if 0
5764         /*
5765          * I don't think call-level stats are being collected yet
5766          * for the File Server.
5767          */
5768         dataBytes = sizeof(struct afs_Stats);
5769         dataBuffP = (afs_int32 *)malloc(dataBytes);
5770         memcpy(dataBuffP, &afs_cmstats, dataBytes);
5771         a_dataP->AFS_CollData_len = dataBytes>>2;
5772         a_dataP->AFS_CollData_val = dataBuffP;
5773 #else
5774         a_dataP->AFS_CollData_len = 0;
5775         a_dataP->AFS_CollData_val = NULL;
5776 #endif /* 0 */
5777         break;
5778
5779       case AFS_XSTATSCOLL_PERF_INFO:
5780         /*
5781          * Pass back all the regular performance-related data.
5782          *
5783          * >>> We are forced to allocate a separate area in which to
5784          * >>> put this stuff in by the RPC stub generator, since it
5785          * >>> will be freed at the tail end of the server stub code.
5786          */
5787
5788         afs_perfstats.numPerfCalls++;
5789         FillPerfValues(&afs_perfstats);
5790
5791         /*
5792          * Don't overwrite the spares at the end.
5793          */
5794
5795         dataBytes = sizeof(struct afs_PerfStats);
5796         dataBuffP = (afs_int32 *)malloc(dataBytes);
5797         memcpy(dataBuffP, &afs_perfstats, dataBytes);
5798         a_dataP->AFS_CollData_len = dataBytes>>2;
5799         a_dataP->AFS_CollData_val = dataBuffP;
5800         break;
5801
5802       case AFS_XSTATSCOLL_FULL_PERF_INFO:
5803         /*
5804          * Pass back the full collection of performance-related data.
5805          * We have to stuff the basic, overall numbers in, but the
5806          * detailed numbers are kept in the structure already.
5807          *
5808          * >>> We are forced to allocate a separate area in which to
5809          * >>> put this stuff in by the RPC stub generator, since it
5810          * >>> will be freed at the tail end of the server stub code.
5811          */
5812
5813         afs_perfstats.numPerfCalls++;
5814 #if FS_STATS_DETAILED
5815         afs_FullPerfStats.overall.numPerfCalls = afs_perfstats.numPerfCalls;
5816         FillPerfValues(&afs_FullPerfStats.overall);
5817
5818         /*
5819          * Don't overwrite the spares at the end.
5820          */
5821
5822         dataBytes = sizeof(struct fs_stats_FullPerfStats);
5823         dataBuffP = (afs_int32 *)malloc(dataBytes);
5824         memcpy(dataBuffP, &afs_FullPerfStats, dataBytes);
5825         a_dataP->AFS_CollData_len = dataBytes>>2;
5826         a_dataP->AFS_CollData_val = dataBuffP;
5827 #endif
5828         break;
5829
5830       default:
5831         /*
5832          * Illegal collection number.
5833          */
5834         a_dataP->AFS_CollData_len = 0;
5835         a_dataP->AFS_CollData_val = NULL;
5836         code = 1;
5837     } /*Switch on collection number*/
5838
5839 #if FS_STATS_DETAILED
5840     TM_GetTimeOfDay(&opStopTime, 0);
5841     if (code == 0) {
5842       FS_LOCK
5843       (opP->numSuccesses)++;
5844       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5845       fs_stats_AddTo((opP->sumTime), elapsedTime);
5846       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5847       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5848         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5849       }
5850       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5851         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5852       }
5853       FS_UNLOCK
5854     }
5855
5856 #endif /* FS_STATS_DETAILED */
5857
5858     return(code);
5859
5860 } /*SRXAFS_GetXStats*/
5861
5862
5863 static afs_int32 common_GiveUpCallBacks (struct rx_call *acall,
5864                                          struct AFSCBFids *FidArray,
5865                                          struct AFSCBs *CallBackArray)
5866 {
5867     afs_int32 errorCode = 0;
5868     register int i;
5869     struct client *client;
5870     struct rx_connection *tcon;
5871 #if FS_STATS_DETAILED
5872     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
5873     struct timeval opStartTime,
5874                    opStopTime;              /* Start/stop times for RPC op*/
5875     struct timeval elapsedTime;             /* Transfer time */
5876
5877     /*
5878      * Set our stats pointer, remember when the RPC operation started, and
5879      * tally the operation.
5880      */
5881     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GIVEUPCALLBACKS]);
5882     FS_LOCK
5883     (opP->numOps)++;
5884     FS_UNLOCK
5885     TM_GetTimeOfDay(&opStartTime, 0);
5886 #endif /* FS_STATS_DETAILED */
5887
5888     if (FidArray)
5889         ViceLog(1, ("SAFS_GiveUpCallBacks (Noffids=%d)\n", FidArray->AFSCBFids_len));
5890
5891     FS_LOCK
5892     AFSCallStats.GiveUpCallBacks++, AFSCallStats.TotalCalls++;
5893     FS_UNLOCK
5894     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
5895         goto Bad_GiveUpCallBacks;
5896
5897     if (!FidArray && !CallBackArray) {
5898         ViceLog(1, ("SAFS_GiveUpAllCallBacks: host=%x\n", 
5899                 (tcon->peer ? tcon->peer->host : 0)));
5900         errorCode = GetClient(tcon, &client);
5901         if (!errorCode) 
5902             DeleteAllCallBacks_r(client->host, 1);
5903     } else {
5904         if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) {
5905             ViceLog(0, ("GiveUpCallBacks: #Fids %d < #CallBacks %d, host=%x\n", 
5906                         FidArray->AFSCBFids_len, CallBackArray->AFSCBs_len, 
5907                         (tcon->peer ? tcon->peer->host : 0)));
5908             errorCode = EINVAL;
5909             goto Bad_GiveUpCallBacks;
5910         }
5911
5912         errorCode = GetClient(tcon, &client);
5913         if (!errorCode) {
5914             for (i=0; i < FidArray->AFSCBFids_len; i++) {
5915                 register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]);
5916                 DeleteCallBack(client->host, fid);
5917             }
5918         }
5919     }
5920
5921 Bad_GiveUpCallBacks:
5922     errorCode = CallPostamble(tcon, errorCode);
5923
5924 #if FS_STATS_DETAILED
5925     TM_GetTimeOfDay(&opStopTime, 0);
5926     if (errorCode == 0) {
5927       FS_LOCK
5928       (opP->numSuccesses)++;
5929       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
5930       fs_stats_AddTo((opP->sumTime), elapsedTime);
5931       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
5932       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
5933         fs_stats_TimeAssign((opP->minTime), elapsedTime);
5934       }
5935       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
5936         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
5937       }
5938       FS_UNLOCK
5939     }
5940 #endif /* FS_STATS_DETAILED */
5941 out:
5942     return errorCode;
5943
5944 } /*common_GiveUpCallBacks*/
5945
5946
5947 afs_int32 SRXAFS_GiveUpCallBacks (struct rx_call *acall,
5948                                   struct AFSCBFids *FidArray,
5949                                   struct AFSCBs *CallBackArray)
5950 {
5951     return common_GiveUpCallBacks(acall, FidArray, CallBackArray);
5952 } /*SRXAFS_GiveUpCallBacks*/
5953
5954 afs_int32 SRXAFS_GiveUpAllCallBacks (struct rx_call *acall)
5955 {
5956     return common_GiveUpCallBacks(acall, 0, 0);
5957 } /*SRXAFS_GiveUpAllCallBacks*/
5958
5959
5960 afs_int32 SRXAFS_NGetVolumeInfo (struct rx_call *acall,
5961                                  char *avolid,
5962                                  struct AFSVolumeInfo *avolinfo)
5963 {
5964     return(VNOVOL);             /* XXX Obsolete routine XXX */
5965
5966 } /*SRXAFS_NGetVolumeInfo*/
5967
5968
5969 /*
5970  * Dummy routine. Should never be called (the cache manager should only 
5971  * invoke this interface when communicating with a AFS/DFS Protocol
5972  * Translator).
5973  */
5974 afs_int32 SRXAFS_Lookup(struct rx_call *call_p,
5975                         struct AFSFid *afs_dfid_p,
5976                         char *afs_name_p,
5977                         struct AFSFid *afs_fid_p,
5978                         struct AFSFetchStatus *afs_status_p,
5979                         struct AFSFetchStatus *afs_dir_status_p,
5980                         struct AFSCallBack *afs_callback_p,
5981                         struct AFSVolSync *afs_sync_p)
5982 {
5983     return EINVAL;
5984 }
5985
5986
5987 afs_int32 SRXAFS_GetCapabilities(struct rx_call *acall,
5988                                  Capabilities *capabilities)
5989 {
5990     afs_int32 *dataBuffP;               
5991     afs_int32 *dataP;
5992     afs_int32 dataBytes;   
5993
5994     dataBytes = 1 * sizeof(afs_int32);
5995     dataBuffP = (afs_int32 *)malloc(dataBytes);
5996     dataBuffP[0] = CAPABILITY_ERRORTRANS;
5997     capabilities->Capabilities_len = dataBytes/sizeof(afs_int32);
5998     capabilities->Capabilities_val = dataBuffP;
5999
6000     return 0;
6001
6002
6003 afs_int32 SRXAFS_FlushCPS(struct rx_call *acall,
6004                           struct ViceIds *vids,
6005                           struct IPAddrs *addrs,
6006                           afs_int32 spare1,
6007                           afs_int32 *spare2, 
6008                           afs_int32 *spare3)
6009 {
6010     int i;
6011     afs_int32 nids, naddrs;
6012     afs_int32 *vd, *addr;
6013     int     errorCode = 0;              /* return code to caller */
6014     struct client *client;
6015     struct rx_connection *tcon = rx_ConnectionOf(acall);
6016
6017     ViceLog(1, ("SRXAFS_FlushCPS\n"));
6018     FS_LOCK
6019     AFSCallStats.TotalCalls++;
6020     FS_UNLOCK
6021     nids = vids->ViceIds_len;   /* # of users in here */
6022     naddrs = addrs->IPAddrs_len;        /* # of hosts in here */
6023     if (nids < 0 || naddrs < 0) {
6024         errorCode = EINVAL;
6025         goto Bad_FlushCPS;
6026     }
6027
6028     vd = vids->ViceIds_val;
6029     for (i=0; i<nids; i++, vd++) {
6030       if (!*vd)
6031         continue;
6032       client = h_ID2Client(*vd);  /* returns client locked, or NULL */
6033       if (!client)
6034         continue;
6035
6036       BoostSharedLock(&client->lock);
6037       client->prfail = 2;       /* Means re-eval client's cps */
6038 #ifdef  notdef
6039       if (client->tcon) {
6040         rx_SetRock(((struct rx_connection *) client->tcon), 0);
6041       }
6042 #endif
6043       if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
6044         free(client->CPS.prlist_val);
6045         client->CPS.prlist_val = NULL;
6046         client->CPS.prlist_len = 0;
6047       }
6048       ReleaseWriteLock(&client->lock);
6049     }
6050
6051     addr = addrs->IPAddrs_val;
6052     for (i=0; i<naddrs; i++, addr++) {
6053       if (*addr)
6054         h_flushhostcps(*addr, htons(7001));
6055     }
6056
6057 Bad_FlushCPS:
6058     ViceLog(2, ("SAFS_FlushCPS  returns %d\n", errorCode)); 
6059     return errorCode;
6060 } /*SRXAFS_FlushCPS */
6061
6062 /* worthless hack to let CS keep running ancient software */
6063 static int afs_vtoi(register char *aname)
6064 {
6065     register afs_int32 temp;
6066     register int tc;
6067
6068     temp = 0;
6069     while((tc = *aname++)) {
6070         if (tc > '9' || tc < '0') return 0; /* invalid name */
6071         temp *= 10;
6072         temp += tc - '0';
6073     }
6074     return temp;
6075 }
6076
6077 /*
6078  * may get name or #, but must handle all weird cases (recognize readonly
6079  * or backup volumes by name or #
6080  */
6081 static afs_int32 CopyVolumeEntry(char *aname,register struct vldbentry *ave,
6082                                  register struct VolumeInfo *av)
6083 {
6084     register int i, j, vol;
6085     afs_int32 mask, whichType;
6086     afs_uint32 *serverHost, *typePtr;
6087     
6088     /* figure out what type we want if by name */
6089     i = strlen(aname);
6090     if (i >= 8 && strcmp(aname+i-7, ".backup") == 0)
6091         whichType = BACKVOL;
6092     else if (i >= 10 && strcmp(aname+i-9, ".readonly")==0)
6093         whichType = ROVOL;
6094     else whichType = RWVOL;
6095     
6096     vol = afs_vtoi(aname);
6097     if (vol == 0) vol = ave->volumeId[whichType];
6098     
6099     /*
6100      * Now vol has volume # we're interested in.  Next, figure out the type
6101      * of the volume by looking finding it in the vldb entry
6102      */
6103     if ((ave->flags&VLF_RWEXISTS) && vol == ave->volumeId[RWVOL]) {
6104         mask = VLSF_RWVOL;
6105         whichType = RWVOL;
6106     }
6107     else if ((ave->flags&VLF_ROEXISTS) && vol == ave->volumeId[ROVOL]) {
6108         mask = VLSF_ROVOL;
6109         whichType = ROVOL;
6110     }
6111     else if ((ave->flags&VLF_BACKEXISTS) && vol == ave->volumeId[BACKVOL]) {
6112         mask = VLSF_RWVOL;  /* backup always is on the same volume as parent */
6113         whichType = BACKVOL;
6114     }
6115     else
6116         return  EINVAL;     /* error: can't find volume in vldb entry */
6117     
6118     typePtr = &av->Type0;
6119     serverHost = &av->Server0;
6120     av->Vid = vol;
6121     av->Type = whichType;
6122     av->Type0 = av->Type1 = av->Type2 = av->Type3 = av->Type4 = 0;
6123     if (ave->flags & VLF_RWEXISTS) typePtr[RWVOL] = ave->volumeId[RWVOL];
6124     if (ave->flags & VLF_ROEXISTS) typePtr[ROVOL] = ave->volumeId[ROVOL];
6125     if (ave->flags & VLF_BACKEXISTS) typePtr[BACKVOL] = ave->volumeId[BACKVOL];
6126
6127     for(i=0,j=0; i<ave->nServers; i++) {
6128         if ((ave->serverFlags[i] & mask) == 0) continue;    /* wrong volume */
6129         serverHost[j] = ave->serverNumber[i];
6130         j++;
6131     }
6132     av->ServerCount = j;
6133     if (j < 8) serverHost[j++] = 0; /* bogus 8, but compat only now */
6134     return 0;
6135 }
6136
6137 static afs_int32 TryLocalVLServer(char *avolid, struct VolumeInfo *avolinfo)
6138 {
6139     static struct rx_connection *vlConn = 0;
6140     static int down = 0;
6141     static afs_int32 lastDownTime = 0;
6142     struct vldbentry tve;
6143     struct rx_securityClass *vlSec;
6144     register afs_int32 code;
6145
6146     if (!vlConn) {
6147         vlSec = rxnull_NewClientSecurityObject();
6148         vlConn = rx_NewConnection(htonl(0x7f000001), htons(7003), 52, vlSec, 0);
6149         rx_SetConnDeadTime(vlConn, 15); /* don't wait long */
6150     }
6151     if (down && (FT_ApproxTime() < lastDownTime + 180)) {
6152         return 1;   /* failure */
6153     }
6154
6155     code = VL_GetEntryByNameO(vlConn, avolid, &tve);
6156     if (code >= 0) down = 0;    /* call worked */
6157     if (code) {
6158         if (code < 0) {
6159             lastDownTime = FT_ApproxTime(); /* last time we tried an RPC */
6160             down = 1;
6161         }
6162         return code;
6163     }
6164
6165     /* otherwise convert to old format vldb entry */
6166     code = CopyVolumeEntry(avolid, &tve, avolinfo);
6167     return code;
6168 }
6169
6170
6171
6172
6173
6174
6175 afs_int32 SRXAFS_GetVolumeInfo (struct rx_call *acall,
6176                                 char *avolid,
6177                                 struct VolumeInfo *avolinfo)
6178 {
6179     afs_int32 code;
6180     struct rx_connection *tcon;
6181 #if FS_STATS_DETAILED
6182     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6183     struct timeval opStartTime,
6184                    opStopTime;              /* Start/stop times for RPC op*/
6185     struct timeval elapsedTime;             /* Transfer time */
6186
6187     /*
6188      * Set our stats pointer, remember when the RPC operation started, and
6189      * tally the operation.
6190      */
6191     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMEINFO]);
6192     FS_LOCK
6193     (opP->numOps)++;
6194     FS_UNLOCK
6195     TM_GetTimeOfDay(&opStartTime, 0);
6196 #endif /* FS_STATS_DETAILED */
6197     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6198         goto Bad_GetVolumeInfo;
6199
6200     FS_LOCK
6201     AFSCallStats.GetVolumeInfo++, AFSCallStats.TotalCalls++;
6202     FS_UNLOCK
6203
6204     code = TryLocalVLServer(avolid, avolinfo);
6205     ViceLog(1, ("SAFS_GetVolumeInfo returns %d, Volume %u, type %x, servers %x %x %x %x...\n",
6206                 code, avolinfo->Vid, avolinfo->Type,
6207                 avolinfo->Server0, avolinfo->Server1, avolinfo->Server2,
6208                 avolinfo->Server3));
6209     avolinfo->Type4     = 0xabcd9999;   /* tell us to try new vldb */
6210
6211 Bad_GetVolumeInfo:
6212     code = CallPostamble(tcon, code);
6213
6214 #if FS_STATS_DETAILED
6215     TM_GetTimeOfDay(&opStopTime, 0);
6216     if (code == 0) {
6217       FS_LOCK
6218       (opP->numSuccesses)++;
6219       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6220       fs_stats_AddTo((opP->sumTime), elapsedTime);
6221       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6222       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6223         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6224       }
6225       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6226         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6227       }
6228       FS_UNLOCK
6229     }
6230
6231 #endif /* FS_STATS_DETAILED */
6232
6233     return code;
6234
6235 } /*SRXAFS_GetVolumeInfo*/
6236
6237
6238 afs_int32 SRXAFS_GetVolumeStatus(struct rx_call *acall,
6239                                  afs_int32 avolid,
6240                                  AFSFetchVolumeStatus *FetchVolStatus,
6241                                  char **Name,
6242                                  char **OfflineMsg,
6243                                  char **Motd)
6244 {
6245     Vnode * targetptr = 0;              /* vnode of the new file */
6246     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6247     int     errorCode = 0;              /* error code */
6248     Volume * volptr = 0;                /* pointer to the volume header */
6249     struct client * client;             /* pointer to client entry */
6250     afs_int32 rights, anyrights;                /* rights for this and any user */
6251     AFSFid  dummyFid;
6252     struct rx_connection *tcon;
6253 #if FS_STATS_DETAILED
6254     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6255     struct timeval opStartTime,
6256                    opStopTime;              /* Start/stop times for RPC op*/
6257     struct timeval elapsedTime;             /* Transfer time */
6258
6259     /*
6260      * Set our stats pointer, remember when the RPC operation started, and
6261      * tally the operation.
6262      */
6263     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETVOLUMESTATUS]);
6264     FS_LOCK
6265     (opP->numOps)++;
6266     FS_UNLOCK
6267     TM_GetTimeOfDay(&opStartTime, 0);
6268 #endif /* FS_STATS_DETAILED */
6269
6270     ViceLog(1,("SAFS_GetVolumeStatus for volume %u\n", avolid));
6271     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6272         goto Bad_GetVolumeStatus;
6273
6274     FS_LOCK
6275     AFSCallStats.GetVolumeStatus++, AFSCallStats.TotalCalls++;
6276     FS_UNLOCK
6277
6278     if (avolid == 0) {
6279         errorCode = EINVAL;
6280         goto Bad_GetVolumeStatus;
6281     }
6282     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6283
6284     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6285                                      MustBeDIR, &parentwhentargetnotdir,
6286                                      &client, READ_LOCK, &rights, &anyrights)))
6287         goto Bad_GetVolumeStatus;
6288
6289     if ((VanillaUser(client)) && (!(rights & PRSFS_READ))) {
6290         errorCode = EACCES;
6291         goto Bad_GetVolumeStatus;
6292     }
6293     RXGetVolumeStatus(FetchVolStatus, Name, OfflineMsg, Motd, volptr);
6294
6295 Bad_GetVolumeStatus:
6296     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6297     ViceLog(2,("SAFS_GetVolumeStatus returns %d\n",errorCode));
6298     /* next is to guarantee out strings exist for stub */
6299     if (*Name == 0) {*Name = (char *) malloc(1); **Name = 0;}
6300     if (*Motd == 0) {*Motd = (char *) malloc(1); **Motd = 0;}
6301     if (*OfflineMsg == 0) {*OfflineMsg = (char *) malloc(1); **OfflineMsg = 0;}
6302     errorCode = CallPostamble(tcon, errorCode);
6303
6304 #if FS_STATS_DETAILED
6305     TM_GetTimeOfDay(&opStopTime, 0);
6306     if (errorCode == 0) {
6307       FS_LOCK
6308       (opP->numSuccesses)++;
6309       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6310       fs_stats_AddTo((opP->sumTime), elapsedTime);
6311       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6312       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6313         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6314       }
6315       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6316         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6317       }
6318       FS_UNLOCK
6319     }
6320
6321 #endif /* FS_STATS_DETAILED */
6322     return(errorCode);
6323
6324 } /*SRXAFS_GetVolumeStatus*/
6325
6326
6327 afs_int32 SRXAFS_SetVolumeStatus (struct rx_call *acall,
6328                                   afs_int32 avolid,
6329                                   AFSStoreVolumeStatus *StoreVolStatus,
6330                                   char *Name,
6331                                   char *OfflineMsg,
6332                                   char *Motd)
6333 {
6334     Vnode * targetptr = 0;              /* vnode of the new file */
6335     Vnode * parentwhentargetnotdir = 0; /* vnode of parent */
6336     int     errorCode = 0;              /* error code */
6337     Volume * volptr = 0;                /* pointer to the volume header */
6338     struct client * client;             /* pointer to client entry */
6339     afs_int32 rights, anyrights;                /* rights for this and any user */
6340     AFSFid  dummyFid;
6341     struct rx_connection *tcon = rx_ConnectionOf(acall);
6342 #if FS_STATS_DETAILED
6343     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6344     struct timeval opStartTime,
6345                    opStopTime;              /* Start/stop times for RPC op*/
6346     struct timeval elapsedTime;             /* Transfer time */
6347
6348     /*
6349      * Set our stats pointer, remember when the RPC operation started, and
6350      * tally the operation.
6351      */
6352     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETVOLUMESTATUS]);
6353     FS_LOCK
6354     (opP->numOps)++;
6355     FS_UNLOCK
6356     TM_GetTimeOfDay(&opStartTime, 0);
6357 #endif /* FS_STATS_DETAILED */
6358
6359     ViceLog(1,("SAFS_SetVolumeStatus for volume %u\n", avolid));
6360     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon)))
6361         goto Bad_SetVolumeStatus;
6362
6363     FS_LOCK
6364     AFSCallStats.SetVolumeStatus++, AFSCallStats.TotalCalls++;
6365     FS_UNLOCK
6366
6367     if (avolid == 0) {
6368         errorCode = EINVAL;
6369         goto Bad_SetVolumeStatus;
6370     }
6371     dummyFid.Volume = avolid, dummyFid.Vnode = (afs_int32)ROOTVNODE, dummyFid.Unique = 1;
6372
6373     if ((errorCode = GetVolumePackage(tcon, &dummyFid, &volptr, &targetptr,
6374                                      MustBeDIR, &parentwhentargetnotdir,
6375                                      &client, READ_LOCK, &rights, &anyrights)))
6376         goto Bad_SetVolumeStatus;
6377
6378     if (readonlyServer) {
6379         errorCode = VREADONLY;
6380         goto Bad_SetVolumeStatus;
6381     }
6382     if (VanillaUser(client)) {
6383         errorCode = EACCES;
6384         goto Bad_SetVolumeStatus;
6385     }
6386
6387     errorCode = RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name,
6388                                       OfflineMsg, Motd);
6389
6390  Bad_SetVolumeStatus:
6391     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
6392     ViceLog(2,("SAFS_SetVolumeStatus returns %d\n",errorCode));
6393     errorCode = CallPostamble(tcon, errorCode);
6394
6395 #if FS_STATS_DETAILED
6396     TM_GetTimeOfDay(&opStopTime, 0);
6397     if (errorCode == 0) {
6398       FS_LOCK
6399       (opP->numSuccesses)++;
6400       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6401       fs_stats_AddTo((opP->sumTime), elapsedTime);
6402       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6403       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6404         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6405       }
6406       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6407         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6408       }
6409       FS_UNLOCK
6410     }
6411
6412 #endif /* FS_STATS_DETAILED */
6413
6414     osi_auditU (acall, SetVolumeStatusEvent, errorCode, AUD_LONG, avolid, AUD_STR, Name, AUD_END);
6415     return(errorCode);
6416
6417 } /*SRXAFS_SetVolumeStatus*/
6418
6419 #define DEFAULTVOLUME   "root.afs"
6420
6421 afs_int32 SRXAFS_GetRootVolume (struct rx_call *acall, char **VolumeName)
6422 {
6423     int fd;
6424     int len;
6425     char *temp;
6426     int errorCode = 0;          /* error code */
6427     struct rx_connection *tcon;
6428 #if FS_STATS_DETAILED
6429     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6430     struct timeval opStartTime,
6431                    opStopTime;              /* Start/stop times for RPC op*/
6432     struct timeval elapsedTime;             /* Transfer time */
6433
6434     /*
6435      * Set our stats pointer, remember when the RPC operation started, and
6436      * tally the operation.
6437      */
6438     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETROOTVOLUME]);
6439     FS_LOCK
6440     (opP->numOps)++;
6441     FS_UNLOCK
6442     TM_GetTimeOfDay(&opStartTime, 0);
6443 #endif /* FS_STATS_DETAILED */
6444
6445     return FSERR_EOPNOTSUPP;
6446
6447 #ifdef  notdef
6448     if (errorCode = CallPreamble(acall, ACTIVECALL, &tcon))
6449         goto Bad_GetRootVolume;
6450     FS_LOCK
6451     AFSCallStats.GetRootVolume++, AFSCallStats.TotalCalls++;
6452     FS_UNLOCK
6453
6454     temp = malloc(256);
6455     fd = open(AFSDIR_SERVER_ROOTVOL_FILEPATH, O_RDONLY, 0666);
6456     if (fd <= 0)
6457         strcpy(temp, DEFAULTVOLUME);
6458     else {
6459 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6460         lockf(fd, F_LOCK, 0);
6461 #else
6462         flock(fd, LOCK_EX);
6463 #endif
6464         len = read(fd, temp, 256);
6465 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
6466         lockf(fd, F_ULOCK, 0);
6467 #else
6468         flock(fd, LOCK_UN);
6469 #endif
6470         close(fd);
6471         if (temp[len-1] == '\n') len--;
6472         temp[len] = '\0';
6473     }
6474     *VolumeName = temp;     /* freed by rx server-side stub */
6475
6476 Bad_GetRootVolume:
6477     errorCode = CallPostamble(tcon, errorCode);
6478
6479 #if FS_STATS_DETAILED
6480     TM_GetTimeOfDay(&opStopTime, 0);
6481     if (errorCode == 0) {
6482       FS_LOCK
6483       (opP->numSuccesses)++;
6484       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6485       fs_stats_AddTo((opP->sumTime), elapsedTime);
6486       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6487       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6488         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6489       }
6490       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6491         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6492       }
6493       FS_UNLOCK
6494     }
6495 #endif /* FS_STATS_DETAILED */
6496
6497     return(errorCode);
6498 #endif  /* notdef */
6499
6500 } /*SRXAFS_GetRootVolume*/
6501
6502
6503 /* still works because a struct CBS is the same as a struct AFSOpaque */
6504 afs_int32 SRXAFS_CheckToken (struct rx_call *acall,
6505                              afs_int32 AfsId,
6506                              struct AFSOpaque *Token)
6507 {
6508     afs_int32 code;
6509     struct rx_connection *tcon;
6510 #if FS_STATS_DETAILED
6511     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6512     struct timeval opStartTime,
6513                    opStopTime;              /* Start/stop times for RPC op*/
6514     struct timeval elapsedTime;             /* Transfer time */
6515
6516     /*
6517      * Set our stats pointer, remember when the RPC operation started, and
6518      * tally the operation.
6519      */
6520     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CHECKTOKEN]);
6521     FS_LOCK
6522     (opP->numOps)++;
6523     FS_UNLOCK
6524     TM_GetTimeOfDay(&opStartTime, 0);
6525 #endif /* FS_STATS_DETAILED */
6526
6527     if ((code = CallPreamble(acall, ACTIVECALL, &tcon)))
6528         goto Bad_CheckToken;
6529
6530     code = FSERR_ECONNREFUSED;
6531     
6532 Bad_CheckToken:
6533     code = CallPostamble(tcon, code);
6534
6535 #if FS_STATS_DETAILED
6536     TM_GetTimeOfDay(&opStopTime, 0);
6537     if (code == 0) {
6538       FS_LOCK
6539       (opP->numSuccesses)++;
6540       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6541       fs_stats_AddTo((opP->sumTime), elapsedTime);
6542       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6543       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6544         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6545       }
6546       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6547         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6548       }
6549       FS_UNLOCK
6550     }
6551
6552 #endif /* FS_STATS_DETAILED */
6553
6554     return code;
6555
6556 } /*SRXAFS_CheckToken*/
6557
6558 afs_int32 SRXAFS_GetTime (struct rx_call *acall,
6559                           afs_uint32 *Seconds,
6560                           afs_uint32 *USeconds)
6561 {
6562     afs_int32 code;
6563     struct rx_connection *tcon;
6564     struct timeval tpl;
6565 #if FS_STATS_DETAILED
6566     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
6567     struct timeval opStartTime,
6568                    opStopTime;              /* Start/stop times for RPC op*/
6569     struct timeval elapsedTime;             /* Transfer time */
6570
6571     /*
6572      * Set our stats pointer, remember when the RPC operation started, and
6573      * tally the operation.
6574      */
6575     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_GETTIME]);
6576     FS_LOCK
6577     (opP->numOps)++;
6578     FS_UNLOCK
6579     TM_GetTimeOfDay(&opStartTime, 0);
6580 #endif /* FS_STATS_DETAILED */
6581
6582     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon)))
6583         goto Bad_GetTime;
6584
6585     FS_LOCK
6586     AFSCallStats.GetTime++, AFSCallStats.TotalCalls++;
6587     FS_UNLOCK
6588
6589     TM_GetTimeOfDay(&tpl, 0);
6590     *Seconds = tpl.tv_sec;
6591     *USeconds = tpl.tv_usec;
6592
6593     ViceLog(2, ("SAFS_GetTime returns %d, %d\n", *Seconds, *USeconds));
6594     
6595 Bad_GetTime:
6596     code = CallPostamble(tcon, code);
6597
6598 #if FS_STATS_DETAILED
6599     TM_GetTimeOfDay(&opStopTime, 0);
6600     fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
6601     if (code == 0) {
6602       FS_LOCK
6603       (opP->numSuccesses)++;
6604       fs_stats_AddTo((opP->sumTime), elapsedTime);
6605       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
6606       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
6607         fs_stats_TimeAssign((opP->minTime), elapsedTime);
6608       }
6609       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
6610         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
6611       }
6612       FS_UNLOCK
6613     }
6614
6615 #endif /* FS_STATS_DETAILED */
6616
6617     return code;
6618
6619 } /*SRXAFS_GetTime*/
6620
6621
6622 /*
6623  * FetchData_RXStyle
6624  *
6625  * Purpose:
6626  *      Implement a client's data fetch using Rx.
6627  *
6628  * Arguments:
6629  *      volptr          : Ptr to the given volume's info.
6630  *      targetptr       : Pointer to the vnode involved.
6631  *      Call            : Ptr to the Rx call involved.
6632  *      Pos             : Offset within the file.
6633  *      Len             : Length in bytes to read; this value is bogus!
6634  * if FS_STATS_DETAILED
6635  *      a_bytesToFetchP : Set to the number of bytes to be fetched from
6636  *                        the File Server.
6637  *      a_bytesFetchedP : Set to the actual number of bytes fetched from
6638  *                        the File Server.
6639  * endif
6640  */
6641
6642 afs_int32
6643 FetchData_RXStyle(Volume *volptr, 
6644                   Vnode *targetptr, 
6645                   register struct rx_call *Call,
6646                   afs_size_t Pos,
6647                   afs_size_t Len,
6648                   afs_int32 Int64Mode,
6649 #if FS_STATS_DETAILED
6650                   afs_size_t *a_bytesToFetchP,
6651                   afs_size_t *a_bytesFetchedP
6652 #endif /* FS_STATS_DETAILED */
6653                   )
6654 {
6655     struct timeval StartTime, StopTime; /* used to calculate file  transfer rates */
6656     int errorCode = 0;                  /* Returned error code to caller */
6657     int code;
6658     IHandle_t *ihP;
6659     FdHandle_t *fdP;
6660 #ifdef AFS_NT40_ENV
6661     register char *tbuffer;
6662 #else /* AFS_NT40_ENV */
6663     struct iovec tiov[RX_MAXIOVECS];
6664     int tnio;
6665 #endif /* AFS_NT40_ENV */
6666     afs_size_t tlen;
6667     afs_int32 optSize;
6668     struct stat tstat;
6669 #ifdef  AFS_AIX_ENV
6670     struct statfs tstatfs;
6671 #endif
6672
6673 #if FS_STATS_DETAILED
6674     /*
6675      * Initialize the byte count arguments.
6676      */
6677     (*a_bytesToFetchP) = 0;
6678     (*a_bytesFetchedP) = 0;
6679 #endif /* FS_STATS_DETAILED */
6680
6681 #ifdef AFS_LARGEFILE_ENV
6682     ViceLog(25, ("FetchData_RXStyle: Pos (0X%x,0X%x), Len (0X%x,0X%x)\n",
6683                  (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
6684                  (unsigned) (Len >> 32), (unsigned) (Len & 0xffffffff)));
6685 #else /* !AFS_LARGEFILE_ENV */
6686     ViceLog(25, ("FetchData_RXStyle: Pos 0X%x, Len 0X%x\n",
6687                  (unsigned) Pos,
6688                  (unsigned) Len));
6689 #endif /* !AFS_LARGEFILE_ENV */
6690
6691     if (!VN_GET_INO(targetptr)) {
6692         afs_int32       zero = htonl(0);
6693         /*
6694          * This is used for newly created files; we simply send 0 bytes
6695          * back to make the cache manager happy...
6696          */
6697         if (Int64Mode)
6698             rx_Write(Call, (char *)&zero, sizeof(afs_int32));   /* send 0-length  */
6699         rx_Write(Call, (char *)&zero, sizeof(afs_int32));       /* send 0-length  */
6700         return (0);
6701     }
6702     TM_GetTimeOfDay(&StartTime, 0);
6703     ihP = targetptr->handle;
6704     fdP = IH_OPEN(ihP);
6705     if (fdP == NULL) return EIO;
6706     optSize = sendBufSize;
6707     tlen = FDH_SIZE(fdP);
6708 #ifdef AFS_LARGEFILE_ENV
6709     ViceLog( 25, ("FetchData_RXStyle: file size (0X%x,0X%x)\n",
6710              (unsigned) (tlen >> 32), (unsigned) (tlen & 0xffffffff)));
6711 #else /* !AFS_LARGEFILE_ENV */
6712     ViceLog( 25, ("FetchData_RXStyle: file size 0X%x\n",
6713                   (unsigned) tlen));
6714 #endif /* !AFS_LARGEFILE_ENV */
6715     if (tlen < 0) {
6716         FDH_CLOSE(fdP);
6717         return EIO;
6718     }
6719
6720     if (Pos + Len > tlen) Len = tlen - Pos;     /* get length we should send */
6721     FDH_SEEK(fdP, Pos, 0);
6722     {
6723         afs_int32       high, low;
6724         SplitOffsetOrSize(Len, high, low);
6725         assert(Int64Mode || high==0);
6726         if (Int64Mode) {
6727             high = htonl(high);
6728             rx_Write(Call, (char *)&high, sizeof(afs_int32)); /* High order bits */
6729         }
6730         low = htonl(low);
6731         rx_Write(Call, (char *)&low, sizeof(afs_int32));        /* send length on fetch */
6732     }
6733 #if FS_STATS_DETAILED
6734     (*a_bytesToFetchP) = Len;
6735 #endif /* FS_STATS_DETAILED */
6736 #ifdef AFS_NT40_ENV
6737     tbuffer = AllocSendBuffer();
6738 #endif /* AFS_NT40_ENV */
6739     while (Len > 0) {
6740         if (Len > optSize) tlen = optSize;
6741         else tlen = Len;
6742 #ifdef AFS_NT40_ENV
6743         errorCode = FDH_READ(fdP, tbuffer, tlen);
6744         if (errorCode != tlen) {
6745             FDH_CLOSE(fdP);
6746             FreeSendBuffer((struct afs_buffer *) tbuffer);
6747             return EIO;
6748         }
6749         errorCode = rx_Write(Call, tbuffer, tlen);
6750 #else /* AFS_NT40_ENV */
6751         errorCode = rx_WritevAlloc(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
6752         if (errorCode <= 0) {
6753             FDH_CLOSE(fdP);
6754             return EIO;
6755         }
6756         tlen = errorCode;
6757         errorCode = FDH_READV(fdP, tiov, tnio);
6758         if (errorCode != tlen) {
6759             FDH_CLOSE(fdP);
6760             return EIO;
6761         }
6762         errorCode = rx_Writev(Call, tiov, tnio, tlen);
6763 #endif /* AFS_NT40_ENV */
6764 #if FS_STATS_DETAILED
6765         /*
6766           * Bump the number of bytes actually sent by the number from this
6767           * latest iteration
6768           */
6769         (*a_bytesFetchedP) += errorCode;
6770 #endif /* FS_STATS_DETAILED */
6771         if (errorCode != tlen) {
6772             FDH_CLOSE(fdP);
6773 #ifdef AFS_NT40_ENV
6774             FreeSendBuffer((struct afs_buffer *) tbuffer);
6775 #endif /* AFS_NT40_ENV */
6776             return -31;
6777         }
6778         Len -= tlen;
6779     }
6780 #ifdef AFS_NT40_ENV
6781     FreeSendBuffer((struct afs_buffer *) tbuffer);
6782 #endif /* AFS_NT40_ENV */
6783     FDH_CLOSE(fdP);
6784     TM_GetTimeOfDay(&StopTime, 0);
6785
6786     /* Adjust all Fetch Data related stats */
6787     FS_LOCK
6788     if (AFSCallStats.TotalFetchedBytes > 2000000000) /* Reset if over 2 billion */
6789         AFSCallStats.TotalFetchedBytes = AFSCallStats.AccumFetchTime = 0;
6790     AFSCallStats.AccumFetchTime += ((StopTime.tv_sec - StartTime.tv_sec) * 1000) +
6791       ((StopTime.tv_usec - StartTime.tv_usec) / 1000);
6792     {
6793         afs_size_t      targLen;
6794         VN_GET_LEN(targLen, targetptr);
6795         AFSCallStats.TotalFetchedBytes += targLen;
6796         AFSCallStats.FetchSize1++;
6797         if (targLen < SIZE2)
6798             AFSCallStats.FetchSize2++;  
6799         else if (targLen < SIZE3)
6800             AFSCallStats.FetchSize3++;
6801         else if (targLen < SIZE4)
6802             AFSCallStats.FetchSize4++;  
6803         else
6804             AFSCallStats.FetchSize5++;
6805     }
6806     FS_UNLOCK
6807     return (0);
6808
6809 } /*FetchData_RXStyle*/
6810
6811 static int GetLinkCountAndSize(Volume *vp, FdHandle_t *fdP, int *lc, afs_size_t *size)
6812 {
6813 #ifdef AFS_NAMEI_ENV
6814     FdHandle_t *lhp;
6815     lhp = IH_OPEN(V_linkHandle(vp));
6816     if (!lhp)
6817         return EIO;
6818 #ifdef AFS_NT40_ENV
6819     *lc = nt_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6820 #else
6821     *lc = namei_GetLinkCount(lhp, fdP->fd_ih->ih_ino, 0);
6822 #endif
6823     FDH_CLOSE(lhp);
6824     if (*lc < 0 )
6825         return -1;
6826     *size = OS_SIZE(fdP->fd_fd);
6827     return (*size == -1) ? -1 : 0;
6828 #else
6829     struct stat status;
6830
6831     if (fstat(fdP->fd_fd, &status)<0) {
6832         return -1;
6833     }
6834
6835     *lc = GetLinkCount(vp, &status);
6836     *size = status.st_size;
6837     return 0;
6838 #endif   
6839 }
6840
6841 /*
6842  * StoreData_RXStyle
6843  *
6844  * Purpose:
6845  *      Implement a client's data store using Rx.
6846  *
6847  * Arguments:
6848  *      volptr          : Ptr to the given volume's info.
6849  *      targetptr       : Pointer to the vnode involved.
6850  *      Call            : Ptr to the Rx call involved.
6851  *      Pos             : Offset within the file.
6852  *      Len             : Length in bytes to store; this value is bogus!
6853  * if FS_STATS_DETAILED
6854  *      a_bytesToStoreP : Set to the number of bytes to be stored to
6855  *                        the File Server.
6856  *      a_bytesStoredP  : Set to the actual number of bytes stored to
6857  *                        the File Server.
6858  * endif
6859  */
6860 afs_int32
6861 StoreData_RXStyle(Volume *volptr,
6862                   Vnode *targetptr,
6863                   struct AFSFid *Fid,
6864                   struct client *client,
6865                   register struct rx_call *Call,
6866                   afs_offs_t Pos,
6867                   afs_offs_t Length,
6868                   afs_offs_t FileLength,
6869                   int sync,
6870 #if FS_STATS_DETAILED
6871                   afs_size_t *a_bytesToStoreP,
6872                   afs_size_t *a_bytesStoredP
6873 #endif /* FS_STATS_DETAILED */
6874                   )
6875 {
6876     afs_size_t bytesTransfered;         /* number of bytes actually transfered */
6877     struct timeval StartTime, StopTime; /* Used to measure how long the store takes */
6878     int errorCode = 0;                  /* Returned error code to caller */
6879 #ifdef AFS_NT40_ENV
6880     register char *tbuffer;             /* data copying buffer */
6881 #else /* AFS_NT40_ENV */
6882     struct iovec tiov[RX_MAXIOVECS];    /* no data copying with iovec */
6883     int tnio;                           /* temp for iovec size */
6884 #endif /* AFS_NT40_ENV */
6885     afs_size_t  tlen;                   /* temp for xfr length */
6886     Inode tinode;                       /* inode for I/O */
6887     afs_size_t optSize;                 /* optimal transfer size */
6888     afs_size_t DataLength;              /* size of inode */
6889     afs_size_t TruncatedLength;         /* size after ftruncate */
6890     afs_offs_t NewLength;               /* size after this store completes */
6891     afs_size_t adjustSize;              /* bytes to call VAdjust... with */
6892     int linkCount;                      /* link count on inode */
6893     int code;
6894     FdHandle_t *fdP;
6895     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
6896
6897 #if FS_STATS_DETAILED
6898     /*
6899      * Initialize the byte count arguments.
6900      */
6901     (*a_bytesToStoreP) = 0;
6902     (*a_bytesStoredP)  = 0;
6903 #endif /* FS_STATS_DETAILED */
6904
6905     /*
6906      * We break the callbacks here so that the following signal will not
6907      * leave a window.
6908      */
6909     BreakCallBack(client->host, Fid, 0);
6910
6911     if (Pos == -1 || VN_GET_INO(targetptr) == 0) {
6912         /* the inode should have been created in Alloc_NewVnode */
6913         logHostAddr.s_addr = rx_HostOf(rx_PeerOf(rx_ConnectionOf(Call)));
6914         ViceLog(0, ("StoreData_RXStyle : Inode non-existent Fid = %u.%d.%d, inode = %d, Pos %d Host %s\n",
6915                 Fid->Volume, Fid->Vnode, Fid->Unique, 
6916                 VN_GET_INO(targetptr), Pos, inet_ntoa(logHostAddr) ));
6917         return ENOENT;  /* is this proper error code? */
6918     }
6919     else {
6920         /*
6921          * See if the file has several links (from other volumes).  If it
6922          * does, then we have to make a copy before changing it to avoid
6923          *changing read-only clones of this dude
6924          */
6925         ViceLog(25, ("StoreData_RXStyle : Opening inode %s\n",
6926                      PrintInode(NULL, VN_GET_INO(targetptr))));
6927         fdP = IH_OPEN(targetptr->handle);
6928         if (fdP == NULL) 
6929             return ENOENT;
6930         if (GetLinkCountAndSize(volptr, fdP, &linkCount,
6931                                 &DataLength)<0) {
6932             FDH_CLOSE(fdP);
6933             return EIO;
6934         }
6935         
6936         if (linkCount != 1) {
6937             afs_size_t size;
6938             ViceLog(25, ("StoreData_RXStyle : inode %s has more than onelink\n",
6939                          PrintInode(NULL, VN_GET_INO(targetptr))));
6940             /* other volumes share this data, better copy it first */
6941
6942             /* Adjust the disk block count by the creation of the new inode.
6943              * We call the special VDiskUsage so we don't adjust the volume's
6944              * quota since we don't want to penalyze the user for afs's internal
6945              * mechanisms (i.e. copy on write overhead.) Also the right size
6946              * of the disk will be recorded...
6947              */
6948             FDH_CLOSE(fdP);
6949             VN_GET_LEN(size, targetptr);
6950             volptr->partition->flags &= ~PART_DONTUPDATE;
6951             VSetPartitionDiskUsage(volptr->partition);
6952             volptr->partition->flags |= PART_DONTUPDATE;
6953             if ((errorCode = VDiskUsage(volptr, nBlocks(size)))) {
6954                 volptr->partition->flags &= ~PART_DONTUPDATE;
6955                 return(errorCode);
6956             }
6957
6958             ViceLog(25, ("StoreData : calling CopyOnWrite on  target dir\n"));
6959             if ((errorCode = CopyOnWrite(targetptr, volptr)))
6960             {
6961                 ViceLog(25, ("StoreData : CopyOnWrite failed\n"));
6962                 volptr->partition->flags &= ~PART_DONTUPDATE;
6963                 return (errorCode);
6964             }
6965             volptr->partition->flags &= ~PART_DONTUPDATE;
6966             VSetPartitionDiskUsage(volptr->partition);
6967             fdP = IH_OPEN(targetptr->handle);
6968             if (fdP == NULL)  {
6969                 ViceLog(25, ("StoreData : Reopen after CopyOnWrite failed\n"));
6970                 return ENOENT;
6971             }
6972         }
6973         tinode = VN_GET_INO(targetptr);
6974     }
6975     assert(VALID_INO(tinode));
6976
6977     /* compute new file length */
6978     NewLength = DataLength;
6979     if (FileLength < NewLength)
6980         /* simulate truncate */
6981         NewLength = FileLength; 
6982     TruncatedLength = NewLength; /* remember length after possible ftruncate */
6983     if (Pos + Length > NewLength)
6984         NewLength = Pos+Length;   /* and write */
6985
6986     /* adjust the disk block count by the difference in the files */
6987     {
6988         afs_size_t      targSize;
6989         VN_GET_LEN(targSize, targetptr);
6990         adjustSize = nBlocks(NewLength) - nBlocks(targSize);
6991     }
6992     if((errorCode = AdjustDiskUsage(volptr, adjustSize,
6993                                    adjustSize - SpareComp(volptr)))) {
6994         FDH_CLOSE(fdP);
6995         return(errorCode);
6996     }
6997
6998     /* can signal cache manager to proceed from close now */
6999     /* this bit means that the locks are set and protections are OK */
7000     rx_SetLocalStatus(Call, 1);
7001
7002     TM_GetTimeOfDay(&StartTime, 0);
7003
7004     optSize = sendBufSize;
7005
7006 #ifdef AFS_LARGEFILE_ENV
7007     ViceLog(25, ("StoreData_RXStyle: Pos (0X%x,0X%x), DataLength (0X%x,0X%x), FileLength (0X%x,0X%x), Length (0X%x,0X%x)\n",
7008                  (unsigned) (Pos >> 32), (unsigned) (Pos & 0xffffffff),
7009                  (unsigned) (DataLength >> 32), (unsigned) (DataLength & 0xffffffff),
7010                  (unsigned) (FileLength >> 32), (unsigned) (FileLength & 0xffffffff),
7011                  (unsigned) (Length >> 32), (unsigned) (Length & 0xffffffff)));
7012 #else /* !AFS_LARGEFILE_ENV */
7013     ViceLog(25, ("StoreData_RXStyle: Pos 0X%x, DataLength 0X%x, FileLength 0X%x, Length 0X%x\n",
7014                  (unsigned) Pos,
7015                  (unsigned) DataLength,
7016                  (unsigned) FileLength,
7017                  (unsigned) Length));
7018 #endif /* !AFS_LARGEFILE_ENV */
7019
7020     /* truncate the file iff it needs it (ftruncate is slow even when its a noop) */
7021     if (FileLength < DataLength) FDH_TRUNC(fdP, FileLength);
7022     if (Pos > 0) FDH_SEEK(fdP, Pos, 0);
7023     bytesTransfered = 0;
7024 #ifdef AFS_NT40_ENV
7025     tbuffer = AllocSendBuffer();
7026 #endif /* AFS_NT40_ENV */
7027     /* if length == 0, the loop below isn't going to do anything, including
7028      * extend the length of the inode, which it must do, since the file system
7029      * assumes that the inode length == vnode's file length.  So, we extend
7030      * the file length manually if need be.  Note that if file is bigger than
7031      * Pos+(Length==0), we dont' have to do anything, and certainly shouldn't
7032      * do what we're going to do below.
7033      */
7034     if (Length == 0 && Pos > TruncatedLength) {
7035         /* Set the file's length; we've already done an lseek to the right
7036          * spot above.
7037          */
7038         errorCode = FDH_WRITE(fdP, &tlen, 1);
7039         if (errorCode != 1) goto done;
7040         errorCode = FDH_TRUNC(fdP, Pos);
7041     }
7042     else {
7043         /* have some data to copy */
7044 #if FS_STATS_DETAILED
7045         (*a_bytesToStoreP) = Length;
7046 #endif /* FS_STATS_DETAILED */
7047         while (1) {
7048             if (bytesTransfered >= Length) {
7049                 errorCode = 0;
7050                 break;
7051             }
7052             tlen = Length -     bytesTransfered;    /* how much more to do */
7053             if (tlen > optSize) tlen = optSize; /* bound by buffer size */
7054 #ifdef AFS_NT40_ENV
7055             errorCode = rx_Read(Call, tbuffer, tlen);
7056 #else /* AFS_NT40_ENV */
7057             errorCode = rx_Readv(Call, tiov, &tnio, RX_MAXIOVECS, tlen);
7058 #endif /* AFS_NT40_ENV */
7059 #if FS_STATS_DETAILED
7060             (*a_bytesStoredP) += errorCode;
7061 #endif /* FS_STATS_DETAILED */
7062             if (errorCode <= 0) {
7063                 errorCode = -32;
7064                 break;
7065             }
7066             tlen = errorCode;
7067 #ifdef AFS_NT40_ENV
7068             errorCode = FDH_WRITE(fdP, tbuffer, tlen);
7069 #else /* AFS_NT40_ENV */
7070             errorCode = FDH_WRITEV(fdP, tiov, tnio);
7071 #endif /* AFS_NT40_ENV */
7072             if (errorCode != tlen) {
7073                 errorCode = VDISKFULL;
7074                 break;
7075             }
7076             bytesTransfered += tlen;
7077         }
7078     }
7079   done:
7080 #ifdef AFS_NT40_ENV
7081     FreeSendBuffer((struct afs_buffer *) tbuffer);
7082 #endif /* AFS_NT40_ENV */
7083     if (sync) {
7084       FDH_SYNC(fdP);
7085     }
7086     if (errorCode) {
7087         afs_size_t      nfSize = FDH_SIZE(fdP);
7088         /* something went wrong: adjust size and return */
7089         VN_SET_LEN(targetptr, nfSize); /* set new file size. */
7090         /* changed_newTime is tested in StoreData to detemine if we
7091          * need to update the target vnode.
7092          */
7093         targetptr->changed_newTime = 1;
7094         FDH_CLOSE(fdP);
7095         /* set disk usage to be correct */
7096         VAdjustDiskUsage(&errorCode, volptr,
7097                          (afs_size_t)(nBlocks(nfSize) - nBlocks(NewLength)), 
7098                          (afs_size_t) 0);
7099         return errorCode;
7100     }
7101     FDH_CLOSE(fdP);
7102
7103     TM_GetTimeOfDay(&StopTime, 0);
7104
7105     VN_SET_LEN(targetptr, NewLength);
7106
7107     /* Update all StoreData related stats */
7108     FS_LOCK
7109     if (AFSCallStats.TotalStoredBytes > 2000000000)     /* reset if over 2 billion */
7110         AFSCallStats.TotalStoredBytes = AFSCallStats.AccumStoreTime = 0;
7111     AFSCallStats.StoreSize1++;                  /* Piggybacked data */
7112     {
7113         afs_size_t      targLen;
7114         VN_GET_LEN(targLen, targetptr);
7115         if (targLen < SIZE2)
7116             AFSCallStats.StoreSize2++;
7117         else if (targLen < SIZE3)
7118             AFSCallStats.StoreSize3++;
7119         else if (targLen < SIZE4)
7120             AFSCallStats.StoreSize4++;
7121         else
7122             AFSCallStats.StoreSize5++;
7123     }
7124     FS_UNLOCK
7125     return(errorCode);
7126
7127 } /*StoreData_RXStyle*/
7128
7129 static int sys2et[512];
7130
7131 void init_sys_error_to_et(void) {
7132     memset(&sys2et, 0, sizeof(sys2et));
7133     sys2et[EPERM] = UAEPERM;
7134     sys2et[ENOENT] = UAENOENT;
7135     sys2et[ESRCH] = UAESRCH;
7136     sys2et[EINTR] = UAEINTR;
7137     sys2et[EIO] = UAEIO;
7138     sys2et[ENXIO] = UAENXIO;
7139     sys2et[E2BIG] = UAE2BIG;
7140     sys2et[ENOEXEC] = UAENOEXEC;
7141     sys2et[EBADF] = UAEBADF;
7142     sys2et[ECHILD] = UAECHILD;
7143     sys2et[EAGAIN] = UAEAGAIN;
7144     sys2et[ENOMEM] = UAENOMEM;
7145     sys2et[EACCES] = UAEACCES;
7146     sys2et[EFAULT] = UAEFAULT;
7147     sys2et[ENOTBLK] = UAENOTBLK;
7148     sys2et[EBUSY] = UAEBUSY;
7149     sys2et[EEXIST] = UAEEXIST;
7150     sys2et[EXDEV] = UAEXDEV;
7151     sys2et[ENODEV] = UAENODEV;
7152     sys2et[ENOTDIR] = UAENOTDIR;
7153     sys2et[EISDIR] = UAEISDIR;
7154     sys2et[EINVAL] = UAEINVAL;
7155     sys2et[ENFILE] = UAENFILE;
7156     sys2et[EMFILE] = UAEMFILE;
7157     sys2et[ENOTTY] = UAENOTTY;
7158     sys2et[ETXTBSY] = UAETXTBSY;
7159     sys2et[EFBIG] = UAEFBIG;
7160     sys2et[ENOSPC] = UAENOSPC;
7161     sys2et[ESPIPE] = UAESPIPE;
7162     sys2et[EROFS] = UAEROFS;
7163     sys2et[EMLINK] = UAEMLINK;
7164     sys2et[EPIPE] = UAEPIPE;
7165     sys2et[EDOM] = UAEDOM;
7166     sys2et[ERANGE] = UAERANGE;
7167     sys2et[EDEADLK] = UAEDEADLK;
7168     sys2et[ENAMETOOLONG] = UAENAMETOOLONG;
7169     sys2et[ENOLCK] = UAENOLCK;
7170     sys2et[ENOSYS] = UAENOSYS;
7171     sys2et[ENOTEMPTY] = UAENOTEMPTY;
7172     sys2et[ELOOP] = UAELOOP;
7173     sys2et[EWOULDBLOCK] = UAEWOULDBLOCK;
7174     sys2et[ENOMSG] = UAENOMSG;
7175     sys2et[EIDRM] = UAEIDRM;
7176     sys2et[ECHRNG] = UAECHRNG;
7177     sys2et[EL2NSYNC] = UAEL2NSYNC;
7178     sys2et[EL3HLT] = UAEL3HLT;
7179     sys2et[EL3RST] = UAEL3RST;
7180     sys2et[ELNRNG] = UAELNRNG;
7181     sys2et[EUNATCH] = UAEUNATCH;
7182     sys2et[ENOCSI] = UAENOCSI;
7183     sys2et[EL2HLT] = UAEL2HLT;
7184     sys2et[EBADE] = UAEBADE;
7185     sys2et[EBADR] = UAEBADR;
7186     sys2et[EXFULL] = UAEXFULL;
7187     sys2et[ENOANO] = UAENOANO;
7188     sys2et[EBADRQC] = UAEBADRQC;
7189     sys2et[EBADSLT] = UAEBADSLT;
7190     sys2et[EDEADLK] = UAEDEADLK;
7191     sys2et[EBFONT] = UAEBFONT;
7192     sys2et[ENOSTR] = UAENOSTR;
7193     sys2et[ENODATA] = UAENODATA;
7194     sys2et[ETIME] = UAETIME;
7195     sys2et[ENOSR] = UAENOSR;
7196     sys2et[ENONET] = UAENONET;
7197     sys2et[ENOPKG] = UAENOPKG;
7198     sys2et[EREMOTE] = UAEREMOTE;
7199     sys2et[ENOLINK] = UAENOLINK;
7200     sys2et[EADV] = UAEADV;
7201     sys2et[ESRMNT] = UAESRMNT;
7202     sys2et[ECOMM] = UAECOMM;
7203     sys2et[EPROTO] = UAEPROTO;
7204     sys2et[EMULTIHOP] = UAEMULTIHOP;
7205     sys2et[EDOTDOT] = UAEDOTDOT;
7206     sys2et[EBADMSG] = UAEBADMSG;
7207     sys2et[EOVERFLOW] = UAEOVERFLOW;
7208     sys2et[ENOTUNIQ] = UAENOTUNIQ;
7209     sys2et[EBADFD] = UAEBADFD;
7210     sys2et[EREMCHG] = UAEREMCHG;
7211     sys2et[ELIBACC] = UAELIBACC;
7212     sys2et[ELIBBAD] = UAELIBBAD;
7213     sys2et[ELIBSCN] = UAELIBSCN;
7214     sys2et[ELIBMAX] = UAELIBMAX;
7215     sys2et[ELIBEXEC] = UAELIBEXEC;
7216     sys2et[EILSEQ] = UAEILSEQ;
7217     sys2et[ERESTART] = UAERESTART;
7218     sys2et[ESTRPIPE] = UAESTRPIPE;
7219     sys2et[EUSERS] = UAEUSERS;
7220     sys2et[ENOTSOCK] = UAENOTSOCK;
7221     sys2et[EDESTADDRREQ] = UAEDESTADDRREQ;
7222     sys2et[EMSGSIZE] = UAEMSGSIZE;
7223     sys2et[EPROTOTYPE] = UAEPROTOTYPE;
7224     sys2et[ENOPROTOOPT] = UAENOPROTOOPT;
7225     sys2et[EPROTONOSUPPORT] = UAEPROTONOSUPPORT;
7226     sys2et[ESOCKTNOSUPPORT] = UAESOCKTNOSUPPORT;
7227     sys2et[EOPNOTSUPP] = UAEOPNOTSUPP;
7228     sys2et[EPFNOSUPPORT] = UAEPFNOSUPPORT;
7229     sys2et[EAFNOSUPPORT] = UAEAFNOSUPPORT;
7230     sys2et[EADDRINUSE] = UAEADDRINUSE;
7231     sys2et[EADDRNOTAVAIL] = UAEADDRNOTAVAIL;
7232     sys2et[ENETDOWN] = UAENETDOWN;
7233     sys2et[ENETUNREACH] = UAENETUNREACH;
7234     sys2et[ENETRESET] = UAENETRESET;
7235     sys2et[ECONNABORTED] = UAECONNABORTED;
7236     sys2et[ECONNRESET] = UAECONNRESET;
7237     sys2et[ENOBUFS] = UAENOBUFS;
7238     sys2et[EISCONN] = UAEISCONN;
7239     sys2et[ENOTCONN] = UAENOTCONN;
7240     sys2et[ESHUTDOWN] = UAESHUTDOWN;
7241     sys2et[ETOOMANYREFS] = UAETOOMANYREFS;
7242     sys2et[ETIMEDOUT] = UAETIMEDOUT;
7243     sys2et[ECONNREFUSED] = UAECONNREFUSED;
7244     sys2et[EHOSTDOWN] = UAEHOSTDOWN;
7245     sys2et[EHOSTUNREACH] = UAEHOSTUNREACH;
7246     sys2et[EALREADY] = UAEALREADY;
7247     sys2et[EINPROGRESS] = UAEINPROGRESS;
7248     sys2et[ESTALE] = UAESTALE;
7249     sys2et[EUCLEAN] = UAEUCLEAN;
7250     sys2et[ENOTNAM] = UAENOTNAM;
7251     sys2et[ENAVAIL] = UAENAVAIL;
7252     sys2et[EISNAM] = UAEISNAM;
7253     sys2et[EREMOTEIO] = UAEREMOTEIO;
7254     sys2et[EDQUOT] = UAEDQUOT;
7255     sys2et[ENOMEDIUM] = UAENOMEDIUM;
7256     sys2et[EMEDIUMTYPE] = UAEMEDIUMTYPE;
7257 }
7258
7259 afs_int32 sys_error_to_et(afs_int32 in) {
7260     if (in < 0 || in > 511) return in;
7261     if (sys2et[in] != 0) return sys2et[in];
7262     return in;
7263 }