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