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