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