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