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