b2dac045f48dfc34107751b4b493abe0967023fd
[openafs.git] / src / viced / afsfileprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*  afs_fileprocs.c - Complete File Server request routines              */
11 /*                                                                       */
12 /*  Information Technology Center                                        */
13 /*  Carnegie Mellon University                                           */
14 /*                                                                       */
15 /*  Date: 8/10/88                                                        */
16 /*                                                                       */
17 /*  Function    - A set of routines to handle the various file Server    */
18 /*                  requests; these routines are invoked by rxgen.       */
19 /*                                                                       */
20 /* ********************************************************************** */
21
22 /*
23  * in Check_PermissionRights, certain privileges are afforded to the owner
24  * of the volume, or the owner of a file.  Are these considered "use of
25  * privilege"?
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30 #include <afs/stds.h>
31
32 #include <roken.h>
33
34 #ifdef  AFS_SGI_ENV
35 #undef SHARED                   /* XXX */
36 #endif
37
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
41
42 #ifdef HAVE_NETINET_IF_ETHER_H
43 #include <netinet/if_ether.h>
44 #endif
45
46 #if !defined(AFS_SGI_ENV) && defined(HAVE_SYS_MAP_H)
47 #include <sys/map.h>
48 #endif
49
50 #ifdef HAVE_SYS_STATFS_H
51 #include <sys/statfs.h>
52 #endif
53
54 #ifdef HAVE_SYS_LOCKF_H
55 #include <sys/lockf.h>
56 #endif
57
58 #ifdef HAVE_SYS_DK_H
59 #include <sys/dk.h>
60 #endif
61
62 #ifdef AFS_HPUX_ENV
63 /* included early because of name conflict on IOPEN */
64 #include <sys/inode.h>
65 #ifdef IOPEN
66 #undef IOPEN
67 #endif
68 #endif /* AFS_HPUX_ENV */
69
70 #include <rx/xdr.h>
71 #include <afs/nfs.h>
72 #include <afs/afs_assert.h>
73 #include <lwp.h>
74 #include <lock.h>
75 #include <afs/afsint.h>
76 #include <afs/vldbint.h>
77 #include <afs/errors.h>
78 #include <afs/ihandle.h>
79 #include <afs/vnode.h>
80 #include <afs/volume.h>
81 #include <afs/ptclient.h>
82 #include <afs/ptuser.h>
83 #include <afs/prs_fs.h>
84 #include <afs/acl.h>
85 #include <rx/rx.h>
86 #include <rx/rx_globals.h>
87
88 #include <afs/cellconfig.h>
89 #include <afs/keys.h>
90
91 #include <afs/partition.h>
92 #include "viced_prototypes.h"
93 #include "viced.h"
94 #include "host.h"
95 #include "callback.h"
96 #include <afs/unified_afs.h>
97 #include <afs/audit.h>
98 #include <afs/afsutil.h>
99 #include <afs/dir.h>
100
101 extern void SetDirHandle(DirHandle * dir, Vnode * vnode);
102 extern void FidZap(DirHandle * file);
103 extern void FidZero(DirHandle * file);
104
105 #ifdef AFS_PTHREAD_ENV
106 pthread_mutex_t fileproc_glock_mutex;
107 #endif /* AFS_PTHREAD_ENV */
108
109 /* Useful local defines used by this module */
110
111 #define DONTCHECK       0
112 #define MustNOTBeDIR    1
113 #define MustBeDIR       2
114
115 #define TVS_SDATA       1
116 #define TVS_SSTATUS     2
117 #define TVS_CFILE       4
118 #define TVS_SLINK       8
119 #define TVS_MKDIR       0x10
120
121 #define CHK_FETCH       0x10
122 #define CHK_FETCHDATA   0x10
123 #define CHK_FETCHACL    0x11
124 #define CHK_FETCHSTATUS 0x12
125 #define CHK_STOREDATA   0x00
126 #define CHK_STOREACL    0x01
127 #define CHK_STORESTATUS 0x02
128
129 #define OWNERREAD       0400
130 #define OWNERWRITE      0200
131 #define OWNEREXEC       0100
132 #ifdef USE_GROUP_PERMS
133 #define GROUPREAD       0040
134 #define GROUPWRITE      0020
135 #define GROUPREXEC      0010
136 #endif
137
138 /* The following errors were not defined in NT. They are given unique
139  * names here to avoid any potential collision.
140  */
141 #define FSERR_ELOOP              90
142 #define FSERR_EOPNOTSUPP        122
143 #define FSERR_ECONNREFUSED      130
144
145 #define NOTACTIVECALL   0
146 #define ACTIVECALL      1
147
148 #define CREATE_SGUID_ADMIN_ONLY 1
149
150 extern struct afsconf_dir *confDir;
151 extern afs_int32 dataVersionHigh;
152
153 extern int SystemId;
154 static struct AFSCallStatistics AFSCallStats;
155 #if FS_STATS_DETAILED
156 struct fs_stats_FullPerfStats afs_FullPerfStats;
157 extern int AnonymousID;
158 #endif /* FS_STATS_DETAILED */
159 #if OPENAFS_VOL_STATS
160 static const char nullString[] = "";
161 #endif /* OPENAFS_VOL_STATS */
162
163 struct afs_FSStats {
164     afs_int32 NothingYet;
165 };
166
167 struct afs_FSStats afs_fsstats;
168
169 int LogLevel = 0;
170 int supported = 1;
171 int Console = 0;
172 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
173 afs_int32 PctSpare;
174 extern afs_int32 implicitAdminRights;
175 extern afs_int32 readonlyServer;
176 extern int CopyOnWrite_calls, CopyOnWrite_off0, CopyOnWrite_size0;
177 extern afs_fsize_t CopyOnWrite_maxsize;
178
179 /*
180  * Externals used by the xstat code.
181  */
182 extern VolPkgStats VStats;
183 extern int CEs, CEBlocks;
184
185 extern int HTs, HTBlocks;
186
187 afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
188                             struct rx_call *Call, afs_sfsize_t Pos,
189                             afs_sfsize_t Len, afs_int32 Int64Mode,
190 #if FS_STATS_DETAILED
191                             afs_sfsize_t * a_bytesToFetchP,
192                             afs_sfsize_t * a_bytesFetchedP
193 #endif                          /* FS_STATS_DETAILED */
194     );
195
196 afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
197                             struct AFSFid *Fid, struct client *client,
198                             struct rx_call *Call, afs_fsize_t Pos,
199                             afs_fsize_t Length, afs_fsize_t FileLength,
200                             int sync,
201 #if FS_STATS_DETAILED
202                             afs_sfsize_t * a_bytesToStoreP,
203                             afs_sfsize_t * a_bytesStoredP
204 #endif                          /* FS_STATS_DETAILED */
205     );
206
207 #ifdef AFS_SGI_XFS_IOPS_ENV
208 #include <afs/xfsattrs.h>
209 static int
210 GetLinkCount(Volume * avp, struct stat *astat)
211 {
212     if (!strcmp("xfs", astat->st_fstype)) {
213         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
214     } else
215         return astat->st_nlink;
216 }
217 #else
218 #define GetLinkCount(V, S) (S)->st_nlink
219 #endif
220
221 afs_int32
222 SpareComp(Volume * avolp)
223 {
224     afs_int32 temp;
225
226     FS_LOCK;
227     if (PctSpare) {
228         temp = V_maxquota(avolp);
229         if (temp == 0) {
230             /* no matter; doesn't check in this case */
231             FS_UNLOCK;
232             return 0;
233         }
234         temp = (temp * PctSpare) / 100;
235         FS_UNLOCK;
236         return temp;
237     } else {
238         FS_UNLOCK;
239         return BlocksSpare;
240     }
241
242 }                               /*SpareComp */
243
244 /*
245  * Set the volume synchronization parameter for this volume.  If it changes,
246  * the Cache Manager knows that the volume must be purged from the stat cache.
247  */
248 static void
249 SetVolumeSync(struct AFSVolSync *async, Volume * avol)
250 {
251     FS_LOCK;
252     /* date volume instance was created */
253     if (async) {
254         if (avol)
255             async->spare1 = avol->header->diskstuff.creationDate;
256         else
257             async->spare1 = 0;
258         async->spare2 = 0;
259         async->spare3 = 0;
260         async->spare4 = 0;
261         async->spare5 = 0;
262         async->spare6 = 0;
263     }
264     FS_UNLOCK;
265 }                               /*SetVolumeSync */
266
267 /**
268  * Verify that the on-disk size for a vnode matches the length in the vnode
269  * index.
270  *
271  * @param[in] vp   Volume pointer
272  * @param[in] vnp  Vnode pointer
273  * @param[in] alen Size of the vnode on disk, if known. If unknown, give -1,
274  *                 and CheckLength itself will determine the on-disk size.
275  *
276  * @return operation status
277  *  @retval 0 lengths match
278  *  @retval nonzero Error; either the lengths do not match or there was an
279  *                  error determining the on-disk size. The volume should be
280  *                  taken offline and salvaged.
281  */
282 static int
283 CheckLength(struct Volume *vp, struct Vnode *vnp, afs_sfsize_t alen)
284 {
285     afs_sfsize_t vlen;
286     VN_GET_LEN(vlen, vnp);
287
288     if (alen < 0) {
289         FdHandle_t *fdP;
290
291         fdP = IH_OPEN(vnp->handle);
292         if (fdP == NULL) {
293             ViceLog(0, ("CheckLength: cannot open inode for fid %lu.%lu.%lu\n",
294                         afs_printable_uint32_lu(vp->hashid),
295                         afs_printable_uint32_lu(Vn_id(vnp)),
296                         afs_printable_uint32_lu(vnp->disk.uniquifier)));
297             return -1;
298         }
299         alen = FDH_SIZE(fdP);
300         FDH_CLOSE(fdP);
301         if (alen < 0) {
302             afs_int64 alen64 = alen;
303             ViceLog(0, ("CheckLength: cannot get size for inode for fid "
304                         "%lu.%lu.%lu; FDH_SIZE returned %" AFS_INT64_FMT "\n",
305                         afs_printable_uint32_lu(vp->hashid),
306                         afs_printable_uint32_lu(Vn_id(vnp)),
307                         afs_printable_uint32_lu(vnp->disk.uniquifier),
308                         alen64));
309             return -1;
310         }
311     }
312
313     if (alen != vlen) {
314         afs_int64 alen64 = alen, vlen64 = vlen;
315         ViceLog(0, ("Fid %lu.%lu.%lu has inconsistent length (index "
316                     "%lld inode %lld ); volume must be salvaged\n",
317                     afs_printable_uint32_lu(vp->hashid),
318                     afs_printable_uint32_lu(Vn_id(vnp)),
319                     afs_printable_uint32_lu(vnp->disk.uniquifier),
320                     vlen64, alen64));
321         return -1;
322     }
323     return 0;
324 }
325
326 /*
327  * Note that this function always returns a held host, so
328  * that CallPostamble can block without the host's disappearing.
329  * Call returns rx connection in passed in *tconn
330  */
331 static int
332 CallPreamble(struct rx_call *acall, int activecall,
333              struct rx_connection **tconn, struct host **ahostp)
334 {
335     struct host *thost;
336     struct client *tclient;
337     int retry_flag = 1;
338     int code = 0;
339     char hoststr[16], hoststr2[16];
340 #ifdef AFS_PTHREAD_ENV
341     struct ubik_client *uclient;
342 #endif
343     *ahostp = NULL;
344
345     if (!tconn) {
346         ViceLog(0, ("CallPreamble: unexpected null tconn!\n"));
347         return -1;
348     }
349     *tconn = rx_ConnectionOf(acall);
350
351     H_LOCK;
352   retry:
353     tclient = h_FindClient_r(*tconn);
354     if (!tclient) {
355         ViceLog(0, ("CallPreamble: Couldn't get CPS. Too many lockers\n"));
356         H_UNLOCK;
357         return VBUSY;
358     }
359     thost = tclient->host;
360     if (tclient->prfail == 1) { /* couldn't get the CPS */
361         if (!retry_flag) {
362             h_ReleaseClient_r(tclient);
363             h_Release_r(thost);
364             ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
365             H_UNLOCK;
366             return -1001;
367         }
368         retry_flag = 0;         /* Retry once */
369
370         /* Take down the old connection and re-read the key file */
371         ViceLog(0,
372                 ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
373 #ifdef AFS_PTHREAD_ENV
374         uclient = (struct ubik_client *)pthread_getspecific(viced_uclient_key);
375
376         /* Is it still necessary to drop this? We hit the net, we should... */
377         H_UNLOCK;
378         if (uclient) {
379             hpr_End(uclient);
380             uclient = NULL;
381         }
382         code = hpr_Initialize(&uclient);
383
384         if (!code)
385             osi_Assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
386         H_LOCK;
387 #else
388         code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
389 #endif
390         if (code) {
391             h_ReleaseClient_r(tclient);
392             h_Release_r(thost);
393             H_UNLOCK;
394             ViceLog(0, ("CallPreamble: couldn't reconnect to ptserver\n"));
395             return -1001;
396         }
397
398         tclient->prfail = 2;    /* Means re-eval client's cps */
399         h_ReleaseClient_r(tclient);
400         h_Release_r(thost);
401         goto retry;
402     }
403
404     tclient->LastCall = thost->LastCall = FT_ApproxTime();
405     if (activecall)             /* For all but "GetTime", "GetStats", and "GetCaps" calls */
406         thost->ActiveCall = thost->LastCall;
407
408     h_Lock_r(thost);
409     if (thost->hostFlags & HOSTDELETED) {
410         ViceLog(3,
411                 ("Discarded a packet for deleted host %s:%d\n",
412                  afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port)));
413         code = VBUSY;           /* raced, so retry */
414     } else if ((thost->hostFlags & VENUSDOWN)
415                || (thost->hostFlags & HFE_LATER)) {
416         if (BreakDelayedCallBacks_r(thost)) {
417             ViceLog(0,
418                     ("BreakDelayedCallbacks FAILED for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
419                      afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2),
420                      ntohs(rxr_PortOf(*tconn))));
421             if (MultiProbeAlternateAddress_r(thost)) {
422                 ViceLog(0,
423                         ("MultiProbe failed to find new address for host %s:%d\n",
424                          afs_inet_ntoa_r(thost->host, hoststr),
425                          ntohs(thost->port)));
426                 code = -1;
427             } else {
428                 ViceLog(0,
429                         ("MultiProbe found new address for host %s:%d\n",
430                          afs_inet_ntoa_r(thost->host, hoststr),
431                          ntohs(thost->port)));
432                 if (BreakDelayedCallBacks_r(thost)) {
433                     ViceLog(0,
434                             ("BreakDelayedCallbacks FAILED AGAIN for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
435                               afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2),
436                               ntohs(rxr_PortOf(*tconn))));
437                     code = -1;
438                 }
439             }
440         }
441     } else {
442         code = 0;
443     }
444
445     h_ReleaseClient_r(tclient);
446     h_Unlock_r(thost);
447     H_UNLOCK;
448     *ahostp = thost;
449     return code;
450
451 }                               /*CallPreamble */
452
453
454 static afs_int32
455 CallPostamble(struct rx_connection *aconn, afs_int32 ret,
456               struct host *ahost)
457 {
458     struct host *thost;
459     struct client *tclient;
460     int translate = 0;
461
462     H_LOCK;
463     tclient = h_FindClient_r(aconn);
464     if (!tclient)
465         goto busyout;
466     thost = tclient->host;
467     if (thost->hostFlags & HERRORTRANS)
468         translate = 1;
469     h_ReleaseClient_r(tclient);
470
471     if (ahost) {
472             if (ahost != thost) {
473                     /* host/client recycle */
474                     char hoststr[16], hoststr2[16];
475                     ViceLog(0, ("CallPostamble: ahost %s:%d (%p) != thost "
476                                 "%s:%d (%p)\n",
477                                 afs_inet_ntoa_r(ahost->host, hoststr),
478                                 ntohs(ahost->port),
479                                 ahost,
480                                 afs_inet_ntoa_r(thost->host, hoststr2),
481                                 ntohs(thost->port),
482                                 thost));
483             }
484             /* return the reference taken in CallPreamble */
485             h_Release_r(ahost);
486     } else {
487             char hoststr[16];
488             ViceLog(0, ("CallPostamble: null ahost for thost %s:%d (%p)\n",
489                         afs_inet_ntoa_r(thost->host, hoststr),
490                         ntohs(thost->port),
491                         thost));
492     }
493
494     /* return the reference taken in local h_FindClient_r--h_ReleaseClient_r
495      * does not decrement refcount on client->host */
496     h_Release_r(thost);
497
498  busyout:
499     H_UNLOCK;
500     return (translate ? sys_error_to_et(ret) : ret);
501 }                               /*CallPostamble */
502
503 /*
504  * Returns the volume and vnode pointers associated with file Fid; the lock
505  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
506  * are incremented and they must be eventualy released.
507  */
508 static afs_int32
509 CheckVnodeWithCall(AFSFid * fid, Volume ** volptr, struct VCallByVol *cbv,
510                    Vnode ** vptr, int lock)
511 {
512     Error fileCode = 0;
513     Error local_errorCode, errorCode = -1;
514     static struct timeval restartedat = { 0, 0 };
515
516     if (fid->Volume == 0 || fid->Vnode == 0)    /* not: || fid->Unique == 0) */
517         return (EINVAL);
518     if ((*volptr) == 0) {
519         extern int VInit;
520
521         while (1) {
522             int restarting =
523 #ifdef AFS_DEMAND_ATTACH_FS
524                 VSALVAGE
525 #else
526                 VRESTARTING
527 #endif
528                 ;
529 #ifdef AFS_PTHREAD_ENV
530             static const struct timespec timeout_ts = { 0, 0 };
531             static const struct timespec * const ts = &timeout_ts;
532 #else
533             static const struct timespec * const ts = NULL;
534 #endif
535
536             errorCode = 0;
537             *volptr = VGetVolumeWithCall(&local_errorCode, &errorCode,
538                                                fid->Volume, ts, cbv);
539             if (!errorCode) {
540                 osi_Assert(*volptr);
541                 break;
542             }
543             if ((errorCode == VOFFLINE) && (VInit < 2)) {
544                 /* The volume we want may not be attached yet because
545                  * the volume initialization is not yet complete.
546                  * We can do several things:
547                  *     1.  return -1, which will cause users to see
548                  *         "connection timed out".  This is more or
549                  *         less the same as always, except that the servers
550                  *         may appear to bounce up and down while they
551                  *         are actually restarting.
552                  *     2.  return VBUSY which will cause clients to
553                  *         sleep and retry for 6.5 - 15 minutes, depending
554                  *         on what version of the CM they are running.  If
555                  *         the file server takes longer than that interval
556                  *         to attach the desired volume, then the application
557                  *         will see an ENODEV or EIO.  This approach has
558                  *         the advantage that volumes which have been attached
559                  *         are immediately available, it keeps the server's
560                  *         immediate backlog low, and the call is interruptible
561                  *         by the user.  Users see "waiting for busy volume."
562                  *     3.  sleep here and retry.  Some people like this approach
563                  *         because there is no danger of seeing errors.  However,
564                  *         this approach only works with a bounded number of
565                  *         clients, since the pending queues will grow without
566                  *         stopping.  It might be better to find a way to take
567                  *         this call and stick it back on a queue in order to
568                  *         recycle this thread for a different request.
569                  *     4.  Return a new error code, which new cache managers will
570                  *         know enough to interpret as "sleep and retry", without
571                  *         the upper bound of 6-15 minutes that is imposed by the
572                  *         VBUSY handling.  Users will see "waiting for
573                  *         busy volume," so they know that something is
574                  *         happening.  Old cache managers must be able to do
575                  *         something reasonable with this, for instance, mark the
576                  *         server down.  Fortunately, any error code < 0
577                  *         will elicit that behavior. See #1.
578                  *     5.  Some combination of the above.  I like doing #2 for 10
579                  *         minutes, followed by #4.  3.1b and 3.2 cache managers
580                  *         will be fine as long as the restart period is
581                  *         not longer than 6.5 minutes, otherwise they may
582                  *         return ENODEV to users.  3.3 cache managers will be
583                  *         fine for 10 minutes, then will return
584                  *         ETIMEDOUT.  3.4 cache managers will just wait
585                  *         until the call works or fails definitively.
586                  *  NB. The problem with 2,3,4,5 is that old clients won't
587                  *  fail over to an alternate read-only replica while this
588                  *  server is restarting.  3.4 clients will fail over right away.
589                  */
590                 if (restartedat.tv_sec == 0) {
591                     /* I'm not really worried about when we restarted, I'm   */
592                     /* just worried about when the first VBUSY was returned. */
593                     FT_GetTimeOfDay(&restartedat, 0);
594                     if (busyonrst) {
595                         FS_LOCK;
596                         afs_perfstats.fs_nBusies++;
597                         FS_UNLOCK;
598                     }
599                     return (busyonrst ? VBUSY : restarting);
600                 } else {
601                     struct timeval now;
602                     FT_GetTimeOfDay(&now, 0);
603                     if ((now.tv_sec - restartedat.tv_sec) < (11 * 60)) {
604                         if (busyonrst) {
605                             FS_LOCK;
606                             afs_perfstats.fs_nBusies++;
607                             FS_UNLOCK;
608                         }
609                         return (busyonrst ? VBUSY : restarting);
610                     } else {
611                         return (restarting);
612                     }
613                 }
614             }
615             /* allow read operations on busy volume.
616              * must check local_errorCode because demand attach fs
617              * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
618             else if (local_errorCode == VBUSY && lock == READ_LOCK) {
619 #ifdef AFS_DEMAND_ATTACH_FS
620                 /* DAFS case is complicated by the fact that local_errorCode can
621                  * be VBUSY in cases where the volume is truly offline */
622                 if (!*volptr) {
623                     /* volume is in VOL_STATE_UNATTACHED */
624                     return (errorCode);
625                 }
626 #endif /* AFS_DEMAND_ATTACH_FS */
627                 errorCode = 0;
628                 break;
629             } else if (errorCode)
630                 return (errorCode);
631         }
632     }
633     osi_Assert(*volptr);
634
635     /* get the vnode  */
636     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
637     if (errorCode)
638         return (errorCode);
639     if ((*vptr)->disk.uniquifier != fid->Unique) {
640         VPutVnode(&fileCode, *vptr);
641         osi_Assert(fileCode == 0);
642         *vptr = 0;
643         return (VNOVNODE);      /* return the right error code, at least */
644     }
645     return (0);
646 }                               /*CheckVnode */
647
648 static_inline afs_int32
649 CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
650 {
651     return CheckVnodeWithCall(fid, volptr, NULL, vptr, lock);
652 }
653
654 /*
655  * This routine returns the ACL associated with the targetptr. If the
656  * targetptr isn't a directory, we access its parent dir and get the ACL
657  * thru the parent; in such case the parent's vnode is returned in
658  * READ_LOCK mode.
659  */
660 static afs_int32
661 SetAccessList(Vnode ** targetptr, Volume ** volume,
662               struct acl_accessList **ACL, int *ACLSize, Vnode ** parent,
663               AFSFid * Fid, int Lock)
664 {
665     if ((*targetptr)->disk.type == vDirectory) {
666         *parent = 0;
667         *ACL = VVnodeACL(*targetptr);
668         *ACLSize = VAclSize(*targetptr);
669         return (0);
670     } else {
671         osi_Assert(Fid != 0);
672         while (1) {
673             VnodeId parentvnode;
674             Error errorCode = 0;
675
676             parentvnode = (*targetptr)->disk.parent;
677             VPutVnode(&errorCode, *targetptr);
678             *targetptr = 0;
679             if (errorCode)
680                 return (errorCode);
681             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
682             if (errorCode)
683                 return (errorCode);
684             *ACL = VVnodeACL(*parent);
685             *ACLSize = VAclSize(*parent);
686             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
687                 return (errorCode);
688             if ((*targetptr)->disk.parent != parentvnode) {
689                 VPutVnode(&errorCode, *parent);
690                 *parent = 0;
691                 if (errorCode)
692                     return (errorCode);
693             } else
694                 return (0);
695         }
696     }
697
698 }                               /*SetAccessList */
699
700 /* Must not be called with H_LOCK held */
701 static void
702 client_CheckRights(struct client *client, struct acl_accessList *ACL,
703                    afs_int32 *rights)
704 {
705     *rights = 0;
706     ObtainReadLock(&client->lock);
707     if (client->CPS.prlist_len > 0 && !client->deleted &&
708         client->host && !(client->host->hostFlags & HOSTDELETED))
709         acl_CheckRights(ACL, &client->CPS, rights);
710     ReleaseReadLock(&client->lock);
711 }
712
713 /* Must not be called with H_LOCK held */
714 static afs_int32
715 client_HasAsMember(struct client *client, afs_int32 id)
716 {
717     afs_int32 code = 0;
718
719     ObtainReadLock(&client->lock);
720     if (client->CPS.prlist_len > 0 && !client->deleted &&
721         client->host && !(client->host->hostFlags & HOSTDELETED))
722         code = acl_IsAMember(id, &client->CPS);
723     ReleaseReadLock(&client->lock);
724     return code;
725 }
726
727 /*
728  * Compare the directory's ACL with the user's access rights in the client
729  * connection and return the user's and everybody else's access permissions
730  * in rights and anyrights, respectively
731  */
732 static afs_int32
733 GetRights(struct client *client, struct acl_accessList *ACL,
734           afs_int32 * rights, afs_int32 * anyrights)
735 {
736     extern prlist SystemAnyUserCPS;
737     afs_int32 hrights = 0;
738 #ifndef AFS_PTHREAD_ENV
739     int code;
740 #endif
741
742     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
743         ViceLog(0, ("CheckRights failed\n"));
744         *anyrights = 0;
745     }
746     *rights = 0;
747
748     client_CheckRights(client, ACL, rights);
749
750     /* wait if somebody else is already doing the getCPS call */
751     H_LOCK;
752     while (client->host->hostFlags & HCPS_INPROGRESS) {
753         client->host->hostFlags |= HCPS_WAITING;        /* I am waiting */
754 #ifdef AFS_PTHREAD_ENV
755         CV_WAIT(&client->host->cond, &host_glock_mutex);
756 #else /* AFS_PTHREAD_ENV */
757         if ((code =
758              LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
759             ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
760 #endif /* AFS_PTHREAD_ENV */
761     }
762
763     if (!client->host->hcps.prlist_len || !client->host->hcps.prlist_val) {
764         char hoststr[16];
765         ViceLog(5,
766                 ("CheckRights: len=%u, for host=%s:%d\n",
767                  client->host->hcps.prlist_len,
768                  afs_inet_ntoa_r(client->host->host, hoststr),
769                  ntohs(client->host->port)));
770     } else
771         acl_CheckRights(ACL, &client->host->hcps, &hrights);
772     H_UNLOCK;
773     /* Allow system:admin the rights given with the -implicit option */
774     if (client_HasAsMember(client, SystemId))
775         *rights |= implicitAdminRights;
776
777     *rights |= hrights;
778     *anyrights |= hrights;
779
780     return (0);
781
782 }                               /*GetRights */
783
784 /*
785  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
786  * a System:Administrator)
787  */
788 static afs_int32
789 VanillaUser(struct client *client)
790 {
791     if (client_HasAsMember(client, SystemId))
792         return (0);             /* not a system administrator, then you're "vanilla" */
793     return (1);
794
795 }                               /*VanillaUser */
796
797
798 /*
799  * This unusual afs_int32-parameter routine encapsulates all volume package related
800  * operations together in a single function; it's called by almost all AFS
801  * interface calls.
802  */
803 static afs_int32
804 GetVolumePackageWithCall(struct rx_connection *tcon, struct VCallByVol *cbv,
805                          AFSFid * Fid, Volume ** volptr, Vnode ** targetptr,
806                          int chkforDir, Vnode ** parent, struct client **client,
807                          int locktype, afs_int32 * rights, afs_int32 * anyrights)
808 {
809     struct acl_accessList *aCL; /* Internal access List */
810     int aCLSize;                /* size of the access list */
811     Error errorCode = 0;                /* return code to caller */
812
813     if ((errorCode = CheckVnodeWithCall(Fid, volptr, cbv, targetptr, locktype)))
814         return (errorCode);
815     if (chkforDir) {
816         if (chkforDir == MustNOTBeDIR
817             && ((*targetptr)->disk.type == vDirectory))
818             return (EISDIR);
819         else if (chkforDir == MustBeDIR
820                  && ((*targetptr)->disk.type != vDirectory))
821             return (ENOTDIR);
822     }
823     if ((errorCode =
824          SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
825                        (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
826                        (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
827         return (errorCode);
828     if (chkforDir == MustBeDIR)
829         osi_Assert((*parent) == 0);
830     if (!(*client)) {
831         if ((errorCode = GetClient(tcon, client)) != 0)
832             return (errorCode);
833         if (!(*client))
834             return (EINVAL);
835     }
836     GetRights(*client, aCL, rights, anyrights);
837     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
838     if ((*targetptr)->disk.type != vDirectory) {
839         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
840         if ((*targetptr)->disk.owner == (*client)->ViceId)
841             (*rights) |= PRSFS_ADMINISTER;
842         else
843             (*rights) &= ~PRSFS_ADMINISTER;
844     }
845 #ifdef ADMIN_IMPLICIT_LOOKUP
846     /* admins get automatic lookup on everything */
847     if (!VanillaUser(*client))
848         (*rights) |= PRSFS_LOOKUP;
849 #endif /* ADMIN_IMPLICIT_LOOKUP */
850     return errorCode;
851
852 }                               /*GetVolumePackage */
853
854 static_inline afs_int32
855 GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
856                  Vnode ** targetptr, int chkforDir, Vnode ** parent,
857                  struct client **client, int locktype, afs_int32 * rights,
858                  afs_int32 * anyrights)
859 {
860     return GetVolumePackageWithCall(tcon, NULL, Fid, volptr, targetptr,
861                                     chkforDir, parent, client, locktype,
862                                     rights, anyrights);
863 }
864
865
866 /*
867  * This is the opposite of GetVolumePackage(), and is always used at the end of
868  * AFS calls to put back all used vnodes and the volume in the proper order!
869  */
870 static void
871 PutVolumePackageWithCall(Vnode * parentwhentargetnotdir, Vnode * targetptr,
872                          Vnode * parentptr, Volume * volptr,
873                          struct client **client, struct VCallByVol *cbv)
874 {
875     Error fileCode = 0;         /* Error code returned by the volume package */
876
877     if (parentwhentargetnotdir) {
878         VPutVnode(&fileCode, parentwhentargetnotdir);
879         osi_Assert(!fileCode || (fileCode == VSALVAGE));
880     }
881     if (targetptr) {
882         VPutVnode(&fileCode, targetptr);
883         osi_Assert(!fileCode || (fileCode == VSALVAGE));
884     }
885     if (parentptr) {
886         VPutVnode(&fileCode, parentptr);
887         osi_Assert(!fileCode || (fileCode == VSALVAGE));
888     }
889     if (volptr) {
890         VPutVolumeWithCall(volptr, cbv);
891     }
892     if (*client) {
893         PutClient(client);
894     }
895 }                               /*PutVolumePackage */
896
897 static_inline void
898 PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
899                  Vnode * parentptr, Volume * volptr, struct client **client)
900 {
901     PutVolumePackageWithCall(parentwhentargetnotdir, targetptr, parentptr,
902                              volptr, client, NULL);
903 }
904
905 static int
906 VolumeOwner(struct client *client, Vnode * targetptr)
907 {
908     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
909
910     if (owner >= 0)
911         return (client->ViceId == owner);
912     else {
913         /*
914          * We don't have to check for host's cps since only regular
915          * viceid are volume owners.
916          */
917         return (client_HasAsMember(client, owner));
918     }
919
920 }                               /*VolumeOwner */
921
922 static int
923 VolumeRootVnode(Vnode * targetptr)
924 {
925     return ((targetptr->vnodeNumber == ROOTVNODE)
926             && (targetptr->disk.uniquifier == 1));
927
928 }                               /*VolumeRootVnode */
929
930 /*
931  * Check if target file has the proper access permissions for the Fetch
932  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
933  * StoreStatus) related calls
934  */
935 /* this code should probably just set a "priv" flag where all the audit events
936  * are now, and only generate the audit event once at the end of the routine,
937  * thus only generating the event if all the checks succeed, but only because
938  * of the privilege       XXX
939  */
940 static afs_int32
941 Check_PermissionRights(Vnode * targetptr, struct client *client,
942                        afs_int32 rights, int CallingRoutine,
943                        AFSStoreStatus * InStatus)
944 {
945     Error errorCode = 0;
946 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
947 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
948 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
949
950     if (CallingRoutine & CHK_FETCH) {
951         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) {
952             if (targetptr->disk.type == vDirectory
953                 || targetptr->disk.type == vSymlink) {
954                 if (!(rights & PRSFS_LOOKUP)
955 #ifdef ADMIN_IMPLICIT_LOOKUP
956                     /* grant admins fetch on all directories */
957                     && VanillaUser(client)
958 #endif /* ADMIN_IMPLICIT_LOOKUP */
959                     && !VolumeOwner(client, targetptr))
960                     return (EACCES);
961             } else {            /* file */
962                 /* must have read access, or be owner and have insert access */
963                 if (!(rights & PRSFS_READ)
964                     && !((OWNSp(client, targetptr) && (rights & PRSFS_INSERT)
965                           && (client->ViceId != AnonymousID))))
966                     return (EACCES);
967             }
968             if (CallingRoutine == CHK_FETCHDATA
969                 && targetptr->disk.type == vFile)
970 #ifdef USE_GROUP_PERMS
971                 if (!OWNSp(client, targetptr)
972                     && !client_HasAsMember(client, targetptr->disk.owner)) {
973                     errorCode =
974                         (((GROUPREAD | GROUPEXEC) & targetptr->disk.modeBits)
975                          ? 0 : EACCES);
976                 } else {
977                     errorCode =
978                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.modeBits)
979                          ? 0 : EACCES);
980                 }
981 #else
982                 /*
983                  * The check with the ownership below is a kludge to allow
984                  * reading of files created with no read permission. The owner
985                  * of the file is always allowed to read it.
986                  */
987                 if ((client->ViceId != targetptr->disk.owner)
988                     && VanillaUser(client))
989                     errorCode =
990                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.
991                           modeBits) ? 0 : EACCES);
992 #endif
993         } else {                /*  !VanillaUser(client) && !FetchData */
994
995             osi_audit(PrivilegeEvent, 0, AUD_ID,
996                       (client ? client->ViceId : 0), AUD_INT, CallingRoutine,
997                       AUD_END);
998         }
999     } else {                    /* a store operation */
1000         if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
1001             && (CallingRoutine != CHK_STOREACL)
1002             && (targetptr->disk.type == vFile)) {
1003             /* bypass protection checks on first store after a create
1004              * for the creator; also prevent chowns during this time
1005              * unless you are a system administrator */
1006           /******  InStatus->Owner && UnixModeBits better be SET!! */
1007             if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
1008                 if (readonlyServer)
1009                     return (VREADONLY);
1010                 else if (VanillaUser(client))
1011                     return (EPERM);     /* Was EACCES */
1012                 else
1013                     osi_audit(PrivilegeEvent, 0, AUD_ID,
1014                               (client ? client->ViceId : 0), AUD_INT,
1015                               CallingRoutine, AUD_END);
1016             }
1017         } else {
1018             if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
1019                 osi_audit(PrivilegeEvent, 0, AUD_ID,
1020                           (client ? client->ViceId : 0), AUD_INT,
1021                           CallingRoutine, AUD_END);
1022             } else {
1023                 if (readonlyServer) {
1024                     return (VREADONLY);
1025                 }
1026                 if (CallingRoutine == CHK_STOREACL) {
1027                     if (!(rights & PRSFS_ADMINISTER)
1028                         && !VolumeOwner(client, targetptr))
1029                         return (EACCES);
1030                 } else {        /* store data or status */
1031                     /* watch for chowns and chgrps */
1032                     if (CHOWN(InStatus, targetptr)
1033                         || CHGRP(InStatus, targetptr)) {
1034                         if (readonlyServer)
1035                             return (VREADONLY);
1036                         else if (VanillaUser(client))
1037                             return (EPERM);     /* Was EACCES */
1038                         else
1039                             osi_audit(PrivilegeEvent, 0, AUD_ID,
1040                                       (client ? client->ViceId : 0), AUD_INT,
1041                                       CallingRoutine, AUD_END);
1042                     }
1043                     /* must be sysadmin to set suid/sgid bits */
1044                     if ((InStatus->Mask & AFS_SETMODE) &&
1045 #ifdef AFS_NT40_ENV
1046                         (InStatus->UnixModeBits & 0xc00) != 0) {
1047 #else
1048                         (InStatus->UnixModeBits & (S_ISUID | S_ISGID)) != 0) {
1049 #endif
1050                         if (readonlyServer)
1051                             return (VREADONLY);
1052                         if (VanillaUser(client))
1053                             return (EACCES);
1054                         else
1055                             osi_audit(PrivSetID, 0, AUD_ID,
1056                                       (client ? client->ViceId : 0), AUD_INT,
1057                                       CallingRoutine, AUD_END);
1058                     }
1059                     if (CallingRoutine == CHK_STOREDATA) {
1060                         if (readonlyServer)
1061                             return (VREADONLY);
1062                         if (!(rights & PRSFS_WRITE))
1063                             return (EACCES);
1064                         /* Next thing is tricky.  We want to prevent people
1065                          * from writing files sans 0200 bit, but we want
1066                          * creating new files with 0444 mode to work.  We
1067                          * don't check the 0200 bit in the "you are the owner"
1068                          * path above, but here we check the bit.  However, if
1069                          * you're a system administrator, we ignore the 0200
1070                          * bit anyway, since you may have fchowned the file,
1071                          * too */
1072 #ifdef USE_GROUP_PERMS
1073                         if ((targetptr->disk.type == vFile)
1074                             && VanillaUser(client)) {
1075                             if (!OWNSp(client, targetptr)
1076                                 && !client_HasAsMember(client, targetptr->disk.owner)) {
1077                                 errorCode =
1078                                     ((GROUPWRITE & targetptr->disk.modeBits)
1079                                      ? 0 : EACCES);
1080                             } else {
1081                                 errorCode =
1082                                     ((OWNERWRITE & targetptr->disk.modeBits)
1083                                      ? 0 : EACCES);
1084                             }
1085                         } else
1086 #endif
1087                             if ((targetptr->disk.type != vDirectory)
1088                                 && (!(targetptr->disk.modeBits & OWNERWRITE))) {
1089                             if (readonlyServer)
1090                                 return (VREADONLY);
1091                             if (VanillaUser(client))
1092                                 return (EACCES);
1093                             else
1094                                 osi_audit(PrivilegeEvent, 0, AUD_ID,
1095                                           (client ? client->ViceId : 0),
1096                                           AUD_INT, CallingRoutine, AUD_END);
1097                         }
1098                     } else {    /* a status store */
1099                         if (readonlyServer)
1100                             return (VREADONLY);
1101                         if (targetptr->disk.type == vDirectory) {
1102                             if (!(rights & PRSFS_DELETE)
1103                                 && !(rights & PRSFS_INSERT))
1104                                 return (EACCES);
1105                         } else {        /* a file  or symlink */
1106                             if (!(rights & PRSFS_WRITE))
1107                                 return (EACCES);
1108                         }
1109                     }
1110                 }
1111             }
1112         }
1113     }
1114     return (errorCode);
1115
1116 }                               /*Check_PermissionRights */
1117
1118
1119 /*
1120  * The Access List information is converted from its internal form in the
1121  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
1122  * external form and returned back to the caller, via the AccessList
1123  * structure
1124  */
1125 static afs_int32
1126 RXFetch_AccessList(Vnode * targetptr, Vnode * parentwhentargetnotdir,
1127                    struct AFSOpaque *AccessList)
1128 {
1129     char *eACL;                 /* External access list placeholder */
1130
1131     if (acl_Externalize_pr
1132         (hpr_IdToName, (targetptr->disk.type ==
1133           vDirectory ? VVnodeACL(targetptr) :
1134           VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
1135         return EIO;
1136     }
1137     if ((strlen(eACL) + 1) > AFSOPAQUEMAX) {
1138         acl_FreeExternalACL(&eACL);
1139         return (E2BIG);
1140     } else {
1141         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
1142         AccessList->AFSOpaque_len = strlen(eACL) + 1;
1143     }
1144     acl_FreeExternalACL(&eACL);
1145     return (0);
1146
1147 }                               /*RXFetch_AccessList */
1148
1149
1150 /*
1151  * The Access List information is converted from its external form in the
1152  * input AccessList structure to the internal representation and copied into
1153  * the target dir's vnode storage.
1154  */
1155 static afs_int32
1156 RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList)
1157 {
1158     struct acl_accessList *newACL;      /* PlaceHolder for new access list */
1159
1160     if (acl_Internalize_pr(hpr_NameToId, AccessList->AFSOpaque_val, &newACL)
1161         != 0)
1162         return (EINVAL);
1163     if ((newACL->size + 4) > VAclSize(targetptr))
1164         return (E2BIG);
1165     memcpy((char *)VVnodeACL(targetptr), (char *)newACL, (int)(newACL->size));
1166     acl_FreeACL(&newACL);
1167     return (0);
1168
1169 }                               /*RXStore_AccessList */
1170
1171
1172 /* In our current implementation, each successive data store (new file
1173  * data version) creates a new inode. This function creates the new
1174  * inode, copies the old inode's contents to the new one, remove the old
1175  * inode (i.e. decrement inode count -- if it's currently used the delete
1176  * will be delayed), and modify some fields (i.e. vnode's
1177  * disk.inodeNumber and cloned)
1178  */
1179 #define COPYBUFFSIZE    8192
1180 #define MAXFSIZE (~(afs_fsize_t) 0)
1181 static int
1182 CopyOnWrite(Vnode * targetptr, Volume * volptr, afs_foff_t off, afs_fsize_t len)
1183 {
1184     Inode ino, nearInode;
1185     ssize_t rdlen;
1186     ssize_t wrlen;
1187     afs_fsize_t size;
1188     afs_foff_t done;
1189     size_t length;
1190     char *buff;
1191     int rc;                     /* return code */
1192     IHandle_t *newH;            /* Use until finished copying, then cp to vnode. */
1193     FdHandle_t *targFdP;        /* Source Inode file handle */
1194     FdHandle_t *newFdP;         /* Dest Inode file handle */
1195
1196     if (targetptr->disk.type == vDirectory)
1197         DFlush();               /* just in case? */
1198
1199     VN_GET_LEN(size, targetptr);
1200     if (size > off)
1201         size -= off;
1202     else
1203         size = 0;
1204     if (size > len)
1205         size = len;
1206
1207     buff = (char *)malloc(COPYBUFFSIZE);
1208     if (buff == NULL) {
1209         return EIO;
1210     }
1211
1212     ino = VN_GET_INO(targetptr);
1213     if (!VALID_INO(ino)) {
1214         free(buff);
1215         VTakeOffline(volptr);
1216         ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1217                     volptr->hashid));
1218         return EIO;
1219     }
1220     targFdP = IH_OPEN(targetptr->handle);
1221     if (targFdP == NULL) {
1222         rc = errno;
1223         ViceLog(0,
1224                 ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n",
1225                  targetptr->vnodeNumber, V_id(volptr), rc));
1226         free(buff);
1227         VTakeOffline(volptr);
1228         return rc;
1229     }
1230
1231     nearInode = VN_GET_INO(targetptr);
1232     ino =
1233         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1234                   VPartitionPath(V_partition(volptr)), nearInode,
1235                   V_id(volptr), targetptr->vnodeNumber,
1236                   targetptr->disk.uniquifier,
1237                   (int)targetptr->disk.dataVersion);
1238     if (!VALID_INO(ino)) {
1239         ViceLog(0,
1240                 ("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n",
1241                  volptr->partition->name, V_id(volptr), errno));
1242         FDH_CLOSE(targFdP);
1243         free(buff);
1244         return ENOSPC;
1245     }
1246     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1247     newFdP = IH_OPEN(newH);
1248     osi_Assert(newFdP != NULL);
1249
1250     done = off;
1251     while (size > 0) {
1252         if (size > COPYBUFFSIZE) {      /* more than a buffer */
1253             length = COPYBUFFSIZE;
1254             size -= COPYBUFFSIZE;
1255         } else {
1256             length = size;
1257             size = 0;
1258         }
1259         rdlen = FDH_PREAD(targFdP, buff, length, done);
1260         if (rdlen == length) {
1261             wrlen = FDH_PWRITE(newFdP, buff, length, done);
1262             done += rdlen;
1263         } else
1264             wrlen = 0;
1265         /*  Callers of this function are not prepared to recover
1266          *  from error that put the filesystem in an inconsistent
1267          *  state. Make sure that we force the volume off-line if
1268          *  we some error other than ENOSPC - 4.29.99)
1269          *
1270          *  In case we are unable to write the required bytes, and the
1271          *  error code indicates that the disk is full, we roll-back to
1272          *  the initial state.
1273          */
1274         if ((rdlen != length) || (wrlen != length)) {
1275             if ((wrlen < 0) && (errno == ENOSPC)) {     /* disk full */
1276                 ViceLog(0,
1277                         ("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1278                          volptr->partition->name, V_id(volptr)));
1279                 /* remove destination inode which was partially copied till now */
1280                 FDH_REALLYCLOSE(newFdP);
1281                 IH_RELEASE(newH);
1282                 FDH_REALLYCLOSE(targFdP);
1283                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1284                 if (!rc) {
1285                     ViceLog(0,
1286                             ("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1287                              rc, V_id(volptr), volptr->partition->name));
1288                     VTakeOffline(volptr);
1289                 }
1290                 free(buff);
1291                 return ENOSPC;
1292             } else {
1293                 /* length, rdlen, and wrlen may or may not be 64-bits wide;
1294                  * since we never do any I/O anywhere near 2^32 bytes at a
1295                  * time, just case to an unsigned int for printing */
1296
1297                 ViceLog(0,
1298                         ("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1299                          V_id(volptr), volptr->partition->name, (unsigned)length, (unsigned)rdlen,
1300                          (unsigned)wrlen, errno));
1301 #if defined(AFS_DEMAND_ATTACH_FS)
1302                 ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
1303 #else
1304                 ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
1305 #endif
1306                 /* Decrement this inode so salvager doesn't find it. */
1307                 FDH_REALLYCLOSE(newFdP);
1308                 IH_RELEASE(newH);
1309                 FDH_REALLYCLOSE(targFdP);
1310                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1311                 free(buff);
1312                 VTakeOffline(volptr);
1313                 return EIO;
1314             }
1315         }
1316 #ifndef AFS_PTHREAD_ENV
1317         IOMGR_Poll();
1318 #endif /* !AFS_PTHREAD_ENV */
1319     }
1320     FDH_REALLYCLOSE(targFdP);
1321     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1322                 V_parentId(volptr));
1323     osi_Assert(!rc);
1324     IH_RELEASE(targetptr->handle);
1325
1326     rc = FDH_SYNC(newFdP);
1327     osi_Assert(rc == 0);
1328     FDH_CLOSE(newFdP);
1329     targetptr->handle = newH;
1330     VN_SET_INO(targetptr, ino);
1331     targetptr->disk.cloned = 0;
1332     /* Internal change to vnode, no user level change to volume - def 5445 */
1333     targetptr->changed_oldTime = 1;
1334     free(buff);
1335     return 0;                   /* success */
1336 }                               /*CopyOnWrite */
1337
1338 static int
1339 CopyOnWrite2(FdHandle_t *targFdP, FdHandle_t *newFdP, afs_foff_t off,
1340              afs_sfsize_t size)
1341 {
1342     char *buff = malloc(COPYBUFFSIZE);
1343     size_t length;
1344     ssize_t rdlen;
1345     ssize_t wrlen;
1346     int rc = 0;
1347     afs_foff_t done = off;
1348
1349     if (size > FDH_SIZE(targFdP) - off)
1350         size = FDH_SIZE(targFdP) - off;
1351
1352     while (size > 0) {
1353         if (size > COPYBUFFSIZE) {      /* more than a buffer */
1354             length = COPYBUFFSIZE;
1355             size -= COPYBUFFSIZE;
1356         } else {
1357             length = size;
1358             size = 0;
1359         }
1360         rdlen = FDH_PREAD(targFdP, buff, length, done);
1361         if (rdlen == length) {
1362             wrlen = FDH_PWRITE(newFdP, buff, length, done);
1363             done += rdlen;
1364         }
1365         else
1366             wrlen = 0;
1367
1368         if ((rdlen != length) || (wrlen != length)) {
1369             /* no error recovery, at the worst we'll have a "hole"
1370              * in the file */
1371             rc = 1;
1372             break;
1373         }
1374     }
1375     free(buff);
1376     return rc;
1377 }
1378
1379
1380 /*
1381  * Common code to handle with removing the Name (file when it's called from
1382  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1383  * given directory, parentptr.
1384  */
1385 int DT1 = 0, DT0 = 0;
1386 static afs_int32
1387 DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
1388              DirHandle * dir, AFSFid * fileFid, char *Name, int ChkForDir)
1389 {
1390     DirHandle childdir;         /* Handle for dir package I/O */
1391     Error errorCode = 0;
1392     int code;
1393     afs_ino_str_t stmp;
1394
1395     /* watch for invalid names */
1396     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1397         return (EINVAL);
1398
1399     if (CheckLength(volptr, parentptr, -1)) {
1400         VTakeOffline_r(volptr);
1401         return VSALVAGE;
1402     }
1403
1404     if (parentptr->disk.cloned) {
1405         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1406         if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {
1407             ViceLog(20,
1408                     ("DeleteTarget %s: CopyOnWrite failed %d\n", Name,
1409                      errorCode));
1410             return errorCode;
1411         }
1412     }
1413
1414     /* check that the file is in the directory */
1415     SetDirHandle(dir, parentptr);
1416     if (Lookup(dir, Name, fileFid))
1417         return (ENOENT);
1418     fileFid->Volume = V_id(volptr);
1419
1420     /* just-in-case check for something causing deadlock */
1421     if (fileFid->Vnode == parentptr->vnodeNumber)
1422         return (EINVAL);
1423
1424     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1425     if (errorCode) {
1426         return (errorCode);
1427     }
1428     if (ChkForDir == MustBeDIR) {
1429         if ((*targetptr)->disk.type != vDirectory)
1430             return (ENOTDIR);
1431     } else if ((*targetptr)->disk.type == vDirectory)
1432         return (EISDIR);
1433
1434     /*osi_Assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
1435     /**
1436       * If the uniquifiers dont match then instead of asserting
1437       * take the volume offline and return VSALVAGE
1438       */
1439     if ((*targetptr)->disk.uniquifier != fileFid->Unique) {
1440         VTakeOffline(volptr);
1441         ViceLog(0,
1442                 ("Volume %u now offline, must be salvaged.\n",
1443                  volptr->hashid));
1444         errorCode = VSALVAGE;
1445         return errorCode;
1446     }
1447
1448     if (ChkForDir == MustBeDIR) {
1449         SetDirHandle(&childdir, *targetptr);
1450         if (IsEmpty(&childdir) != 0)
1451             return (EEXIST);
1452         DZap((afs_int32 *) &childdir);
1453         FidZap(&childdir);
1454         (*targetptr)->delete = 1;
1455     } else if ((--(*targetptr)->disk.linkCount) == 0)
1456         (*targetptr)->delete = 1;
1457     if ((*targetptr)->delete) {
1458         if (VN_GET_INO(*targetptr)) {
1459             DT0++;
1460             IH_REALLYCLOSE((*targetptr)->handle);
1461             errorCode =
1462                 IH_DEC(V_linkHandle(volptr), VN_GET_INO(*targetptr),
1463                        V_parentId(volptr));
1464             IH_RELEASE((*targetptr)->handle);
1465             if (errorCode == -1) {
1466                 ViceLog(0,
1467                         ("DT: inode=%s, name=%s, errno=%d\n",
1468                          PrintInode(stmp, VN_GET_INO(*targetptr)), Name,
1469                          errno));
1470                 if (errno != ENOENT)
1471                 {
1472                     VTakeOffline(volptr);
1473                     ViceLog(0,
1474                             ("Volume %u now offline, must be salvaged.\n",
1475                              volptr->hashid));
1476                     return (EIO);
1477                 }
1478                 DT1++;
1479                 errorCode = 0;
1480             }
1481         }
1482         VN_SET_INO(*targetptr, (Inode) 0);
1483         {
1484             afs_fsize_t adjLength;
1485             VN_GET_LEN(adjLength, *targetptr);
1486             VAdjustDiskUsage(&errorCode, volptr, -(int)nBlocks(adjLength), 0);
1487         }
1488     }
1489
1490     (*targetptr)->changed_newTime = 1;  /* Status change of deleted file/dir */
1491
1492     code = Delete(dir, (char *)Name);
1493     if (code) {
1494         ViceLog(0,
1495                 ("Error %d deleting %s\n", code,
1496                  (((*targetptr)->disk.type ==
1497                    Directory) ? "directory" : "file")));
1498         VTakeOffline(volptr);
1499         ViceLog(0,
1500                 ("Volume %u now offline, must be salvaged.\n",
1501                  volptr->hashid));
1502         if (!errorCode)
1503             errorCode = code;
1504     }
1505
1506     DFlush();
1507     return (errorCode);
1508
1509 }                               /*DeleteTarget */
1510
1511
1512 /*
1513  * This routine updates the parent directory's status block after the
1514  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1515  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1516  * been performed.
1517  */
1518 static void
1519 Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
1520                          int author, int linkcount,
1521 #if FS_STATS_DETAILED
1522                          char a_inSameNetwork
1523 #endif                          /* FS_STATS_DETAILED */
1524     )
1525 {
1526     afs_fsize_t newlength;      /* Holds new directory length */
1527     afs_fsize_t parentLength;
1528     Error errorCode;
1529 #if FS_STATS_DETAILED
1530     Date currDate;              /*Current date */
1531     int writeIdx;               /*Write index to bump */
1532     int timeIdx;                /*Authorship time index to bump */
1533 #endif /* FS_STATS_DETAILED */
1534
1535     parentptr->disk.dataVersion++;
1536     newlength = (afs_fsize_t) Length(dir);
1537     /*
1538      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1539      * (create, symlink, link, makedir) so we need to check if we have enough space
1540      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1541      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1542      */
1543     VN_GET_LEN(parentLength, parentptr);
1544     if (nBlocks(newlength) != nBlocks(parentLength)) {
1545         VAdjustDiskUsage(&errorCode, volptr,
1546                          (nBlocks(newlength) - nBlocks(parentLength)),
1547                          (nBlocks(newlength) - nBlocks(parentLength)));
1548     }
1549     VN_SET_LEN(parentptr, newlength);
1550
1551 #if FS_STATS_DETAILED
1552     /*
1553      * Update directory write stats for this volume.  Note that the auth
1554      * counter is located immediately after its associated ``distance''
1555      * counter.
1556      */
1557     if (a_inSameNetwork)
1558         writeIdx = VOL_STATS_SAME_NET;
1559     else
1560         writeIdx = VOL_STATS_DIFF_NET;
1561     V_stat_writes(volptr, writeIdx)++;
1562     if (author != AnonymousID) {
1563         V_stat_writes(volptr, writeIdx + 1)++;
1564     }
1565
1566     /*
1567      * Update the volume's authorship information in response to this
1568      * directory operation.  Get the current time, decide to which time
1569      * slot this operation belongs, and bump the appropriate slot.
1570      */
1571     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1572     timeIdx =
1573         (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1574          VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1575          VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1576          VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1577          VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : VOL_STATS_TIME_IDX_5);
1578     if (parentptr->disk.author == author) {
1579         V_stat_dirSameAuthor(volptr, timeIdx)++;
1580     } else {
1581         V_stat_dirDiffAuthor(volptr, timeIdx)++;
1582     }
1583 #endif /* FS_STATS_DETAILED */
1584
1585     parentptr->disk.author = author;
1586     parentptr->disk.linkCount = linkcount;
1587     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
1588     parentptr->disk.serverModifyTime = FT_ApproxTime();
1589     parentptr->changed_newTime = 1;     /* vnode changed, write it back. */
1590 }
1591
1592
1593 /*
1594  * Update the target file's (or dir's) status block after the specified
1595  * operation is complete. Note that some other fields maybe updated by
1596  * the individual module.
1597  */
1598
1599 /* XXX INCOMPLETE - More attention is needed here! */
1600 static void
1601 Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
1602                          struct client *client, AFSStoreStatus * InStatus,
1603                          Vnode * parentptr, Volume * volptr,
1604                          afs_fsize_t length)
1605 {
1606 #if FS_STATS_DETAILED
1607     Date currDate;              /*Current date */
1608     int writeIdx;               /*Write index to bump */
1609     int timeIdx;                /*Authorship time index to bump */
1610 #endif /* FS_STATS_DETAILED */
1611
1612     if (Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR)) { /* initialize new file */
1613         targetptr->disk.parent = parentptr->vnodeNumber;
1614         VN_SET_LEN(targetptr, length);
1615         /* targetptr->disk.group =      0;  save some cycles */
1616         targetptr->disk.modeBits = 0777;
1617         targetptr->disk.owner = client->ViceId;
1618         targetptr->disk.dataVersion = 0;        /* consistent with the client */
1619         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1620         /* the inode was created in Alloc_NewVnode() */
1621     }
1622 #if FS_STATS_DETAILED
1623     /*
1624      * Update file write stats for this volume.  Note that the auth
1625      * counter is located immediately after its associated ``distance''
1626      * counter.
1627      */
1628     if (client->InSameNetwork)
1629         writeIdx = VOL_STATS_SAME_NET;
1630     else
1631         writeIdx = VOL_STATS_DIFF_NET;
1632     V_stat_writes(volptr, writeIdx)++;
1633     if (client->ViceId != AnonymousID) {
1634         V_stat_writes(volptr, writeIdx + 1)++;
1635     }
1636
1637     /*
1638      * We only count operations that DON'T involve creating new objects
1639      * (files, symlinks, directories) or simply setting status as
1640      * authorship-change operations.
1641      */
1642     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1643         /*
1644          * Update the volume's authorship information in response to this
1645          * file operation.  Get the current time, decide to which time
1646          * slot this operation belongs, and bump the appropriate slot.
1647          */
1648         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1649         timeIdx =
1650             (currDate <
1651              VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1652              VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1653              VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1654              VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1655              VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1656              VOL_STATS_TIME_IDX_5);
1657         if (targetptr->disk.author == client->ViceId) {
1658             V_stat_fileSameAuthor(volptr, timeIdx)++;
1659         } else {
1660             V_stat_fileDiffAuthor(volptr, timeIdx)++;
1661         }
1662     }
1663 #endif /* FS_STATS_DETAILED */
1664
1665     if (!(Caller & TVS_SSTATUS))
1666         targetptr->disk.author = client->ViceId;
1667     if (Caller & TVS_SDATA) {
1668         targetptr->disk.dataVersion++;
1669         if (VanillaUser(client)) {
1670             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1671 #ifdef CREATE_SGUID_ADMIN_ONLY
1672             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1673 #endif
1674         }
1675     }
1676     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1677         /* store status, must explicitly request to change the date */
1678         if (InStatus->Mask & AFS_SETMODTIME)
1679             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1680     } else {                    /* other: date always changes, but perhaps to what is specified by caller */
1681         targetptr->disk.unixModifyTime =
1682             (InStatus->Mask & AFS_SETMODTIME ? InStatus->
1683              ClientModTime : FT_ApproxTime());
1684     }
1685     if (InStatus->Mask & AFS_SETOWNER) {
1686         /* admin is allowed to do chmod, chown as well as chown, chmod. */
1687         if (VanillaUser(client)) {
1688             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1689 #ifdef CREATE_SGUID_ADMIN_ONLY
1690             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1691 #endif
1692         }
1693         targetptr->disk.owner = InStatus->Owner;
1694         if (VolumeRootVnode(targetptr)) {
1695             Error errorCode = 0;        /* what should be done with this? */
1696
1697             V_owner(targetptr->volumePtr) = InStatus->Owner;
1698             VUpdateVolume(&errorCode, targetptr->volumePtr);
1699         }
1700     }
1701     if (InStatus->Mask & AFS_SETMODE) {
1702         int modebits = InStatus->UnixModeBits;
1703 #define CREATE_SGUID_ADMIN_ONLY 1
1704 #ifdef CREATE_SGUID_ADMIN_ONLY
1705         if (VanillaUser(client))
1706             modebits = modebits & 0777;
1707 #endif
1708         if (VanillaUser(client)) {
1709             targetptr->disk.modeBits = modebits;
1710         } else {
1711             targetptr->disk.modeBits = modebits;
1712             switch (Caller) {
1713             case TVS_SDATA:
1714                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1715                           CHK_STOREDATA, AUD_END);
1716                 break;
1717             case TVS_CFILE:
1718             case TVS_SSTATUS:
1719                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1720                           CHK_STORESTATUS, AUD_END);
1721                 break;
1722             default:
1723                 break;
1724             }
1725         }
1726     }
1727     targetptr->disk.serverModifyTime = FT_ApproxTime();
1728     if (InStatus->Mask & AFS_SETGROUP)
1729         targetptr->disk.group = InStatus->Group;
1730     /* vnode changed : to be written back by VPutVnode */
1731     targetptr->changed_newTime = 1;
1732
1733 }                               /*Update_TargetVnodeStatus */
1734
1735
1736 /*
1737  * Fills the CallBack structure with the expiration time and type of callback
1738  * structure. Warning: this function is currently incomplete.
1739  */
1740 static void
1741 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1742 {
1743     /* CallBackTime could not be 0 */
1744     if (CallBackTime == 0) {
1745         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1746         CallBack->ExpirationTime = 0;
1747     } else
1748         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1749     CallBack->CallBackVersion = CALLBACK_VERSION;
1750     CallBack->CallBackType = CB_SHARED; /* The default for now */
1751
1752 }                               /*SetCallBackStruct */
1753
1754
1755 /*
1756  * Adjusts (Subtract) "length" number of blocks from the volume's disk
1757  * allocation; if some error occured (exceeded volume quota or partition
1758  * was full, or whatever), it frees the space back and returns the code.
1759  * We usually pre-adjust the volume space to make sure that there's
1760  * enough space before consuming some.
1761  */
1762 static afs_int32
1763 AdjustDiskUsage(Volume * volptr, afs_sfsize_t length,
1764                 afs_sfsize_t checkLength)
1765 {
1766     Error rc;
1767     Error nc;
1768
1769     VAdjustDiskUsage(&rc, volptr, length, checkLength);
1770     if (rc) {
1771         VAdjustDiskUsage(&nc, volptr, -length, 0);
1772         if (rc == VOVERQUOTA) {
1773             ViceLog(2,
1774                     ("Volume %u (%s) is full\n", V_id(volptr),
1775                      V_name(volptr)));
1776             return (rc);
1777         }
1778         if (rc == VDISKFULL) {
1779             ViceLog(0,
1780                     ("Partition %s that contains volume %u is full\n",
1781                      volptr->partition->name, V_id(volptr)));
1782             return (rc);
1783         }
1784         ViceLog(0, ("Got error return %d from VAdjustDiskUsage\n", rc));
1785         return (rc);
1786     }
1787     return (0);
1788
1789 }                               /*AdjustDiskUsage */
1790
1791 /*
1792  * Common code that handles the creation of a new file (SAFS_CreateFile and
1793  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1794  */
1795 static afs_int32
1796 Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
1797                Vnode ** targetptr, char *Name, struct AFSFid *OutFid,
1798                int FileType, afs_sfsize_t BlocksPreallocatedForVnode)
1799 {
1800     Error errorCode = 0;                /* Error code returned back */
1801     Error temp;
1802     Inode inode = 0;
1803     Inode nearInode;            /* hint for inode allocation in solaris */
1804     afs_ino_str_t stmp;
1805
1806     if ((errorCode =
1807          AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1808                          BlocksPreallocatedForVnode))) {
1809         ViceLog(25,
1810                 ("Insufficient space to allocate %lld blocks\n",
1811                  (afs_intmax_t) BlocksPreallocatedForVnode));
1812         return (errorCode);
1813     }
1814
1815     if (CheckLength(volptr, parentptr, -1)) {
1816         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1817         VTakeOffline_r(volptr);
1818         return VSALVAGE;
1819     }
1820
1821     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1822     if (errorCode != 0) {
1823         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1824         return (errorCode);
1825     }
1826     OutFid->Volume = V_id(volptr);
1827     OutFid->Vnode = (*targetptr)->vnodeNumber;
1828     OutFid->Unique = (*targetptr)->disk.uniquifier;
1829
1830     nearInode = VN_GET_INO(parentptr);  /* parent is also in same vol */
1831
1832     /* create the inode now itself */
1833     inode =
1834         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1835                   VPartitionPath(V_partition(volptr)), nearInode,
1836                   V_id(volptr), (*targetptr)->vnodeNumber,
1837                   (*targetptr)->disk.uniquifier, 1);
1838
1839     /* error in creating inode */
1840     if (!VALID_INO(inode)) {
1841         ViceLog(0,
1842                 ("Volume : %u vnode = %u Failed to create inode: errno = %d\n",
1843                  (*targetptr)->volumePtr->header->diskstuff.id,
1844                  (*targetptr)->vnodeNumber, errno));
1845         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1846         (*targetptr)->delete = 1;       /* delete vnode */
1847         return ENOSPC;
1848     }
1849     VN_SET_INO(*targetptr, inode);
1850     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1851
1852     /* copy group from parent dir */
1853     (*targetptr)->disk.group = parentptr->disk.group;
1854
1855     if (parentptr->disk.cloned) {
1856         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1857         if ((errorCode = CopyOnWrite(parentptr, volptr, 0, MAXFSIZE))) {        /* disk full */
1858             ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1859             /* delete the vnode previously allocated */
1860             (*targetptr)->delete = 1;
1861             VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1862             IH_REALLYCLOSE((*targetptr)->handle);
1863             if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1864                 ViceLog(0,
1865                         ("Alloc_NewVnode: partition %s idec %s failed\n",
1866                          volptr->partition->name, PrintInode(stmp, inode)));
1867             IH_RELEASE((*targetptr)->handle);
1868
1869             return errorCode;
1870         }
1871     }
1872
1873     /* add the name to the directory */
1874     SetDirHandle(dir, parentptr);
1875     if ((errorCode = Create(dir, (char *)Name, OutFid))) {
1876         (*targetptr)->delete = 1;
1877         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1878         IH_REALLYCLOSE((*targetptr)->handle);
1879         if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1880             ViceLog(0,
1881                     ("Alloc_NewVnode: partition %s idec %s failed\n",
1882                      volptr->partition->name, PrintInode(stmp, inode)));
1883         IH_RELEASE((*targetptr)->handle);
1884         return (errorCode);
1885     }
1886     DFlush();
1887     return (0);
1888
1889 }                               /*Alloc_NewVnode */
1890
1891
1892 /*
1893  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1894  * SAFS_ReleaseLock)
1895  */
1896 static afs_int32
1897 HandleLocking(Vnode * targetptr, struct client *client, afs_int32 rights, ViceLockType LockingType)
1898 {
1899     int Time;                   /* Used for time */
1900     int writeVnode = targetptr->changed_oldTime;        /* save original status */
1901
1902     targetptr->changed_oldTime = 1;     /* locking doesn't affect any time stamp */
1903     Time = FT_ApproxTime();
1904     switch (LockingType) {
1905     case LockRead:
1906     case LockWrite:
1907         if (Time > targetptr->disk.lock.lockTime)
1908             targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount =
1909                 0;
1910         Time += AFS_LOCKWAIT;
1911         if (LockingType == LockRead) {
1912             if ( !(rights & PRSFS_LOCK) &&
1913                  !(rights & PRSFS_WRITE) &&
1914                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1915                     return(EACCES);
1916
1917             if (targetptr->disk.lock.lockCount >= 0) {
1918                 ++(targetptr->disk.lock.lockCount);
1919                 targetptr->disk.lock.lockTime = Time;
1920             } else
1921                 return (EAGAIN);
1922         } else if (LockingType == LockWrite) {
1923             if ( !(rights & PRSFS_WRITE) &&
1924                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1925                 return(EACCES);
1926
1927             if (targetptr->disk.lock.lockCount == 0) {
1928                 targetptr->disk.lock.lockCount = -1;
1929                 targetptr->disk.lock.lockTime = Time;
1930             } else
1931                 return (EAGAIN);
1932         }
1933         break;
1934     case LockExtend:
1935         Time += AFS_LOCKWAIT;
1936         if (targetptr->disk.lock.lockCount != 0)
1937             targetptr->disk.lock.lockTime = Time;
1938         else
1939             return (EINVAL);
1940         break;
1941     case LockRelease:
1942         if ((--targetptr->disk.lock.lockCount) <= 0)
1943             targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime =
1944                 0;
1945         break;
1946     default:
1947         targetptr->changed_oldTime = writeVnode;        /* restore old status */
1948         ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1949     }
1950     return (0);
1951 }                               /*HandleLocking */
1952
1953 /* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
1954
1955 static afs_int32
1956 CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
1957 {
1958     if (readonlyServer)
1959         return (VREADONLY);
1960     if (!(rights & Prfs_Mode))
1961         return (EACCES);
1962     if ((targetptr->disk.type != vDirectory)
1963         && (!(targetptr->disk.modeBits & OWNERWRITE)))
1964         return (EACCES);
1965     return (0);
1966 }
1967
1968 /*
1969  * If some flags (i.e. min or max quota) are set, the volume's in disk
1970  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1971  * update, if applicable.
1972  */
1973 static afs_int32
1974 RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
1975                       char *Name, char *OfflineMsg, char *Motd)
1976 {
1977     Error errorCode = 0;
1978
1979     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1980         V_minquota(volptr) = StoreVolStatus->MinQuota;
1981     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1982         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1983     if (strlen(OfflineMsg) > 0) {
1984         strcpy(V_offlineMessage(volptr), OfflineMsg);
1985     }
1986     if (strlen(Name) > 0) {
1987         strcpy(V_name(volptr), Name);
1988     }
1989 #if OPENAFS_VOL_STATS
1990     /*
1991      * We don't overwrite the motd field, since it's now being used
1992      * for stats
1993      */
1994 #else
1995     if (strlen(Motd) > 0) {
1996         strcpy(V_motd(volptr), Motd);
1997     }
1998 #endif /* FS_STATS_DETAILED */
1999     VUpdateVolume(&errorCode, volptr);
2000     return (errorCode);
2001
2002 }                               /*RXUpdate_VolumeStatus */
2003
2004
2005 static afs_int32
2006 RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
2007                   char **motd, Volume * volptr)
2008 {
2009     int temp;
2010
2011     status->Vid = V_id(volptr);
2012     status->ParentId = V_parentId(volptr);
2013     status->Online = V_inUse(volptr);
2014     status->InService = V_inService(volptr);
2015     status->Blessed = V_blessed(volptr);
2016     status->NeedsSalvage = V_needsSalvaged(volptr);
2017     if (VolumeWriteable(volptr))
2018         status->Type = ReadWrite;
2019     else
2020         status->Type = ReadOnly;
2021     status->MinQuota = V_minquota(volptr);
2022     status->MaxQuota = V_maxquota(volptr);
2023     status->BlocksInUse = V_diskused(volptr);
2024     status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
2025     status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
2026
2027     /* now allocate and copy these things; they're freed by the RXGEN stub */
2028     temp = strlen(V_name(volptr)) + 1;
2029     *name = malloc(temp);
2030     if (!*name) {
2031         ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2032     }
2033     strcpy(*name, V_name(volptr));
2034     temp = strlen(V_offlineMessage(volptr)) + 1;
2035     *offMsg = malloc(temp);
2036     if (!*offMsg) {
2037         ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2038     }
2039     strcpy(*offMsg, V_offlineMessage(volptr));
2040 #if OPENAFS_VOL_STATS
2041     *motd = malloc(1);
2042     if (!*motd) {
2043         ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2044     }
2045     strcpy(*motd, nullString);
2046 #else
2047     temp = strlen(V_motd(volptr)) + 1;
2048     *motd = malloc(temp);
2049     if (!*motd) {
2050         ViceLogThenPanic(0, ("Failed malloc in RXGetVolumeStatus\n"));
2051     }
2052     strcpy(*motd, V_motd(volptr));
2053 #endif /* FS_STATS_DETAILED */
2054     return 0;
2055 }                               /*RXGetVolumeStatus */
2056
2057
2058 static afs_int32
2059 FileNameOK(char *aname)
2060 {
2061     afs_int32 i, tc;
2062     i = strlen(aname);
2063     if (i >= 4) {
2064         /* watch for @sys on the right */
2065         if (strcmp(aname + i - 4, "@sys") == 0)
2066             return 0;
2067     }
2068     while ((tc = *aname++)) {
2069         if (tc == '/')
2070             return 0;           /* very bad character to encounter */
2071     }
2072     return 1;                   /* file name is ok */
2073
2074 }                               /*FileNameOK */
2075
2076
2077 /*
2078  * This variant of symlink is expressly to support the AFS/DFS translator
2079  * and is not supported by the AFS fileserver. We just return EINVAL.
2080  * The cache manager should not generate this call to an AFS cache manager.
2081  */
2082 afs_int32
2083 SRXAFS_DFSSymlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
2084                   char *LinkContents, struct AFSStoreStatus *InStatus,
2085                   struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus,
2086                   struct AFSFetchStatus *OutDirStatus,
2087                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2088 {
2089     return EINVAL;
2090 }
2091
2092 afs_int32
2093 SRXAFS_FsCmd(struct rx_call * acall, struct AFSFid * Fid,
2094                     struct FsCmdInputs * Inputs,
2095                     struct FsCmdOutputs * Outputs)
2096 {
2097     afs_int32 code = 0;
2098
2099     switch (Inputs->command) {
2100     default:
2101         code = EINVAL;
2102     }
2103     ViceLog(1,("FsCmd: cmd = %d, code=%d\n",
2104                         Inputs->command, Outputs->code));
2105     return code;
2106 }
2107
2108 #ifndef HAVE_PIOV
2109 static struct afs_buffer {
2110     struct afs_buffer *next;
2111 } *freeBufferList = 0;
2112 static int afs_buffersAlloced = 0;
2113
2114 static int
2115 FreeSendBuffer(struct afs_buffer *adata)
2116 {
2117     FS_LOCK;
2118     afs_buffersAlloced--;
2119     adata->next = freeBufferList;
2120     freeBufferList = adata;
2121     FS_UNLOCK;
2122     return 0;
2123
2124 }                               /*FreeSendBuffer */
2125
2126 /* allocate space for sender */
2127 static char *
2128 AllocSendBuffer(void)
2129 {
2130     struct afs_buffer *tp;
2131
2132     FS_LOCK;
2133     afs_buffersAlloced++;
2134     if (!freeBufferList) {
2135         char *tmp;
2136         FS_UNLOCK;
2137         tmp = malloc(sendBufSize);
2138         if (!tmp) {
2139             ViceLogThenPanic(0, ("Failed malloc in AllocSendBuffer\n"));
2140         }
2141         return tmp;
2142     }
2143     tp = freeBufferList;
2144     freeBufferList = tp->next;
2145     FS_UNLOCK;
2146     return (char *)tp;
2147
2148 }                               /*AllocSendBuffer */
2149 #endif /* HAVE_PIOV */
2150
2151 /*
2152  * This routine returns the status info associated with the targetptr vnode
2153  * in the AFSFetchStatus structure.  Some of the newer fields, such as
2154  * SegSize and Group are not yet implemented
2155  */
2156 static
2157     void
2158 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
2159           afs_int32 anyrights, Vnode * parentptr)
2160 {
2161     /* initialize return status from a vnode  */
2162     status->InterfaceVersion = 1;
2163     status->SyncCounter = status->dataVersionHigh = status->lockCount =
2164         status->errorCode = 0;
2165     status->ResidencyMask = 1;  /* means for MR-AFS: file in /vicepr-partition */
2166     if (targetptr->disk.type == vFile)
2167         status->FileType = File;
2168     else if (targetptr->disk.type == vDirectory)
2169         status->FileType = Directory;
2170     else if (targetptr->disk.type == vSymlink)
2171         status->FileType = SymbolicLink;
2172     else
2173         status->FileType = Invalid;     /*invalid type field */
2174     status->LinkCount = targetptr->disk.linkCount;
2175     {
2176         afs_fsize_t targetLen;
2177         VN_GET_LEN(targetLen, targetptr);
2178         SplitOffsetOrSize(targetLen, status->Length_hi, status->Length);
2179     }
2180     status->DataVersion = targetptr->disk.dataVersion;
2181     status->Author = targetptr->disk.author;
2182     status->Owner = targetptr->disk.owner;
2183     status->CallerAccess = rights;
2184     status->AnonymousAccess = anyrights;
2185     status->UnixModeBits = targetptr->disk.modeBits;
2186     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2187     status->ParentVnode =
2188         (status->FileType ==
2189          Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2190     status->ParentUnique =
2191         (status->FileType ==
2192          Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2193     status->ServerModTime = targetptr->disk.serverModifyTime;
2194     status->Group = targetptr->disk.group;
2195     status->lockCount = targetptr->disk.lock.lockCount;
2196     status->errorCode = 0;
2197
2198 }                               /*GetStatus */
2199
2200 static
2201   afs_int32
2202 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
2203                    afs_sfsize_t Pos, afs_sfsize_t Len,
2204                    struct AFSFetchStatus *OutStatus,
2205                    struct AFSCallBack *CallBack, struct AFSVolSync *Sync,
2206                    int type)
2207 {
2208     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2209     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if vptr is a file */
2210     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2211     Error errorCode = 0;                /* return code to caller */
2212     Error fileCode = 0;         /* return code from vol package */
2213     Volume *volptr = 0;         /* pointer to the volume */
2214     struct client *client = 0;  /* pointer to the client data */
2215     struct rx_connection *tcon; /* the connection we're part of */
2216     struct host *thost;
2217     afs_int32 rights, anyrights;        /* rights for this and any user */
2218     struct client *t_client = NULL;     /* tmp ptr to client data */
2219     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2220     struct VCallByVol tcbv, *cbv = NULL;
2221 #if FS_STATS_DETAILED
2222     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2223     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2224     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2225     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2226     struct timeval elapsedTime; /* Transfer time */
2227     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2228     afs_sfsize_t bytesXferred;  /* # bytes actually xferred */
2229     int readIdx;                /* Index of read stats array to bump */
2230     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2231
2232     /*
2233      * Set our stats pointers, remember when the RPC operation started, and
2234      * tally the operation.
2235      */
2236     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2237     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2238     FS_LOCK;
2239     (opP->numOps)++;
2240     FS_UNLOCK;
2241     FT_GetTimeOfDay(&opStartTime, 0);
2242 #endif /* FS_STATS_DETAILED */
2243
2244     ViceLog(1,
2245             ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2246              Fid->Unique));
2247     FS_LOCK;
2248     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2249     FS_UNLOCK;
2250     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2251         goto Bad_FetchData;
2252
2253     /* Get ptr to client data for user Id for logging */
2254     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2255     logHostAddr.s_addr = rxr_HostOf(tcon);
2256     ViceLog(5,
2257             ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2258              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2259              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2260
2261     queue_NodeInit(&tcbv);
2262     tcbv.call = acall;
2263     cbv = &tcbv;
2264
2265     /*
2266      * Get volume/vnode for the fetched file; caller's access rights to
2267      * it are also returned
2268      */
2269     if ((errorCode =
2270          GetVolumePackageWithCall(tcon, cbv, Fid, &volptr, &targetptr, DONTCHECK,
2271                           &parentwhentargetnotdir, &client, READ_LOCK,
2272                           &rights, &anyrights)))
2273         goto Bad_FetchData;
2274
2275     SetVolumeSync(Sync, volptr);
2276
2277 #if FS_STATS_DETAILED
2278     /*
2279      * Remember that another read operation was performed.
2280      */
2281     FS_LOCK;
2282     if (client->InSameNetwork)
2283         readIdx = VOL_STATS_SAME_NET;
2284     else
2285         readIdx = VOL_STATS_DIFF_NET;
2286     V_stat_reads(volptr, readIdx)++;
2287     if (client->ViceId != AnonymousID) {
2288         V_stat_reads(volptr, readIdx + 1)++;
2289     }
2290     FS_UNLOCK;
2291 #endif /* FS_STATS_DETAILED */
2292     /* Check whether the caller has permission access to fetch the data */
2293     if ((errorCode =
2294          Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
2295         goto Bad_FetchData;
2296
2297     /*
2298      * Drop the read lock on the parent directory after saving the parent
2299      * vnode information we need to pass to GetStatus
2300      */
2301     if (parentwhentargetnotdir != NULL) {
2302         tparentwhentargetnotdir = *parentwhentargetnotdir;
2303         VPutVnode(&fileCode, parentwhentargetnotdir);
2304         osi_Assert(!fileCode || (fileCode == VSALVAGE));
2305         parentwhentargetnotdir = NULL;
2306     }
2307 #if FS_STATS_DETAILED
2308     /*
2309      * Remember when the data transfer started.
2310      */
2311     FT_GetTimeOfDay(&xferStartTime, 0);
2312 #endif /* FS_STATS_DETAILED */
2313
2314     /* actually do the data transfer */
2315 #if FS_STATS_DETAILED
2316     errorCode =
2317         FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2318                           &bytesToXfer, &bytesXferred);
2319 #else
2320     if ((errorCode =
2321          FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2322         goto Bad_FetchData;
2323 #endif /* FS_STATS_DETAILED */
2324
2325 #if FS_STATS_DETAILED
2326     /*
2327      * At this point, the data transfer is done, for good or ill.  Remember
2328      * when the transfer ended, bump the number of successes/failures, and
2329      * integrate the transfer size and elapsed time into the stats.  If the
2330      * operation failed, we jump to the appropriate point.
2331      */
2332     FT_GetTimeOfDay(&xferStopTime, 0);
2333     FS_LOCK;
2334     (xferP->numXfers)++;
2335     if (!errorCode) {
2336         (xferP->numSuccesses)++;
2337
2338         /*
2339          * Bump the xfer sum by the number of bytes actually sent, NOT the
2340          * target number.
2341          */
2342         tot_bytesXferred += bytesXferred;
2343         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2344         tot_bytesXferred &= 0x3FF;
2345         if (bytesXferred < xferP->minBytes)
2346             xferP->minBytes = bytesXferred;
2347         if (bytesXferred > xferP->maxBytes)
2348             xferP->maxBytes = bytesXferred;
2349
2350         /*
2351          * Tally the size of the object.  Note: we tally the actual size,
2352          * NOT the number of bytes that made it out over the wire.
2353          */
2354         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2355             (xferP->count[0])++;
2356         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2357             (xferP->count[1])++;
2358         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2359             (xferP->count[2])++;
2360         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2361             (xferP->count[3])++;
2362         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2363             (xferP->count[4])++;
2364         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2365             (xferP->count[5])++;
2366         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2367             (xferP->count[6])++;
2368         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2369             (xferP->count[7])++;
2370         else
2371             (xferP->count[8])++;
2372
2373         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2374         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2375         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2376         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2377             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2378         }
2379         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2380             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2381         }
2382     }
2383     FS_UNLOCK;
2384     /*
2385      * Finally, go off to tell our caller the bad news in case the
2386      * fetch failed.
2387      */
2388     if (errorCode)
2389         goto Bad_FetchData;
2390 #endif /* FS_STATS_DETAILED */
2391
2392     /* write back  the OutStatus from the target vnode  */
2393     GetStatus(targetptr, OutStatus, rights, anyrights,
2394               &tparentwhentargetnotdir);
2395
2396     /* if a r/w volume, promise a callback to the caller */
2397     if (VolumeWriteable(volptr))
2398         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2399     else {
2400         struct AFSFid myFid;
2401         memset(&myFid, 0, sizeof(struct AFSFid));
2402         myFid.Volume = Fid->Volume;
2403         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2404     }
2405
2406   Bad_FetchData:
2407     /* Update and store volume/vnode and parent vnodes back */
2408     (void)PutVolumePackageWithCall(parentwhentargetnotdir, targetptr,
2409                                    (Vnode *) 0, volptr, &client, cbv);
2410     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2411     errorCode = CallPostamble(tcon, errorCode, thost);
2412
2413 #if FS_STATS_DETAILED
2414     FT_GetTimeOfDay(&opStopTime, 0);
2415     if (errorCode == 0) {
2416         FS_LOCK;
2417         (opP->numSuccesses)++;
2418         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2419         fs_stats_AddTo((opP->sumTime), elapsedTime);
2420         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2421         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2422             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2423         }
2424         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2425             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2426         }
2427         FS_UNLOCK;
2428     }
2429 #endif /* FS_STATS_DETAILED */
2430
2431     osi_auditU(acall, FetchDataEvent, errorCode,
2432                AUD_ID, t_client ? t_client->ViceId : 0,
2433                AUD_FID, Fid, AUD_END);
2434     return (errorCode);
2435
2436 }                               /*SRXAFS_FetchData */
2437
2438 afs_int32
2439 SRXAFS_FetchData(struct rx_call * acall, struct AFSFid * Fid, afs_int32 Pos,
2440                  afs_int32 Len, struct AFSFetchStatus * OutStatus,
2441                  struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2442 {
2443     return common_FetchData64(acall, Fid, Pos, Len, OutStatus, CallBack,
2444                               Sync, 0);
2445 }
2446
2447 afs_int32
2448 SRXAFS_FetchData64(struct rx_call * acall, struct AFSFid * Fid, afs_int64 Pos,
2449                    afs_int64 Len, struct AFSFetchStatus * OutStatus,
2450                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2451 {
2452     int code;
2453     afs_sfsize_t tPos, tLen;
2454
2455     tPos = (afs_sfsize_t) Pos;
2456     tLen = (afs_sfsize_t) Len;
2457
2458     code =
2459         common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2460                            1);
2461     return code;
2462 }
2463
2464 afs_int32
2465 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2466                 struct AFSOpaque * AccessList,
2467                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2468 {
2469     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2470     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2471     Error errorCode = 0;                /* return error code to caller */
2472     Volume *volptr = 0;         /* pointer to the volume */
2473     struct client *client = 0;  /* pointer to the client data */
2474     afs_int32 rights, anyrights;        /* rights for this and any user */
2475     struct rx_connection *tcon = rx_ConnectionOf(acall);
2476     struct host *thost;
2477     struct client *t_client = NULL;     /* tmp ptr to client data */
2478     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2479 #if FS_STATS_DETAILED
2480     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2481     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2482     struct timeval elapsedTime; /* Transfer time */
2483
2484     /*
2485      * Set our stats pointer, remember when the RPC operation started, and
2486      * tally the operation.
2487      */
2488     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2489     FS_LOCK;
2490     (opP->numOps)++;
2491     FS_UNLOCK;
2492     FT_GetTimeOfDay(&opStartTime, 0);
2493 #endif /* FS_STATS_DETAILED */
2494
2495     ViceLog(1,
2496             ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2497              Fid->Unique));
2498     FS_LOCK;
2499     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2500     FS_UNLOCK;
2501     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2502         goto Bad_FetchACL;
2503
2504     /* Get ptr to client data for user Id for logging */
2505     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2506     logHostAddr.s_addr = rxr_HostOf(tcon);
2507     ViceLog(5,
2508             ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2509              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2510              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2511
2512     AccessList->AFSOpaque_len = 0;
2513     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2514     if (!AccessList->AFSOpaque_val) {
2515         ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2516     }
2517
2518     /*
2519      * Get volume/vnode for the fetched file; caller's access rights to it
2520      * are also returned
2521      */
2522     if ((errorCode =
2523          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2524                           &parentwhentargetnotdir, &client, READ_LOCK,
2525                           &rights, &anyrights)))
2526         goto Bad_FetchACL;
2527
2528     SetVolumeSync(Sync, volptr);
2529
2530     /* Check whether we have permission to fetch the ACL */
2531     if ((errorCode =
2532          Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2533         goto Bad_FetchACL;
2534
2535     /* Get the Access List from the dir's vnode */
2536     if ((errorCode =
2537          RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2538         goto Bad_FetchACL;
2539
2540     /* Get OutStatus back From the target Vnode  */
2541     GetStatus(targetptr, OutStatus, rights, anyrights,
2542               parentwhentargetnotdir);
2543
2544   Bad_FetchACL:
2545     /* Update and store volume/vnode and parent vnodes back */
2546     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2547                            volptr, &client);
2548     ViceLog(2,
2549             ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2550              AccessList->AFSOpaque_val));
2551     errorCode = CallPostamble(tcon, errorCode, thost);
2552
2553 #if FS_STATS_DETAILED
2554     FT_GetTimeOfDay(&opStopTime, 0);
2555     if (errorCode == 0) {
2556         FS_LOCK;
2557         (opP->numSuccesses)++;
2558         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2559         fs_stats_AddTo((opP->sumTime), elapsedTime);
2560         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2561         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2562             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2563         }
2564         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2565             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2566         }
2567         FS_UNLOCK;
2568     }
2569 #endif /* FS_STATS_DETAILED */
2570
2571     osi_auditU(acall, FetchACLEvent, errorCode,
2572                AUD_ID, t_client ? t_client->ViceId : 0,
2573                AUD_FID, Fid,
2574                AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2575     return errorCode;
2576 }                               /*SRXAFS_FetchACL */
2577
2578
2579 /*
2580  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2581  * merged into it when possible.
2582  */
2583 static
2584   afs_int32
2585 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2586                   struct AFSFetchStatus *OutStatus,
2587                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2588 {
2589     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2590     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2591     Error errorCode = 0;                /* return code to caller */
2592     Volume *volptr = 0;         /* pointer to the volume */
2593     struct client *client = 0;  /* pointer to the client data */
2594     afs_int32 rights, anyrights;        /* rights for this and any user */
2595     struct client *t_client = NULL;     /* tmp ptr to client data */
2596     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2597     struct rx_connection *tcon = rx_ConnectionOf(acall);
2598
2599     /* Get ptr to client data for user Id for logging */
2600     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2601     logHostAddr.s_addr = rxr_HostOf(tcon);
2602     ViceLog(1,
2603             ("SAFS_FetchStatus,  Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2604              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2605              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2606     FS_LOCK;
2607     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2608     FS_UNLOCK;
2609     /*
2610      * Get volume/vnode for the fetched file; caller's rights to it are
2611      * also returned
2612      */
2613     if ((errorCode =
2614          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2615                           &parentwhentargetnotdir, &client, READ_LOCK,
2616                           &rights, &anyrights)))
2617         goto Bad_FetchStatus;
2618
2619     /* set volume synchronization information */
2620     SetVolumeSync(Sync, volptr);
2621
2622     /* Are we allowed to fetch Fid's status? */
2623     if (targetptr->disk.type != vDirectory) {
2624         if ((errorCode =
2625              Check_PermissionRights(targetptr, client, rights,
2626                                     CHK_FETCHSTATUS, 0))) {
2627             if (rx_GetCallAbortCode(acall) == errorCode)
2628                 rx_SetCallAbortCode(acall, 0);
2629             goto Bad_FetchStatus;
2630         }
2631     }
2632
2633     /* set OutStatus From the Fid  */
2634     GetStatus(targetptr, OutStatus, rights, anyrights,
2635               parentwhentargetnotdir);
2636
2637     /* If a r/w volume, also set the CallBack state */
2638     if (VolumeWriteable(volptr))
2639         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2640     else {
2641         struct AFSFid myFid;
2642         memset(&myFid, 0, sizeof(struct AFSFid));
2643         myFid.Volume = Fid->Volume;
2644         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2645     }
2646
2647   Bad_FetchStatus:
2648     /* Update and store volume/vnode and parent vnodes back */
2649     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2650                            volptr, &client);
2651     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2652     return errorCode;
2653
2654 }                               /*SAFSS_FetchStatus */
2655
2656
2657 afs_int32
2658 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2659                   struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2660                   struct AFSVolSync * Sync)
2661 {
2662     int i;
2663     afs_int32 nfiles;
2664     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2665     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2666     Error errorCode = 0;                /* return code to caller */
2667     Volume *volptr = 0;         /* pointer to the volume */
2668     struct client *client = 0;  /* pointer to the client data */
2669     afs_int32 rights, anyrights;        /* rights for this and any user */
2670     struct AFSFid *tfid;        /* file id we're dealing with now */
2671     struct rx_connection *tcon = rx_ConnectionOf(acall);
2672     struct host *thost;
2673     struct client *t_client = NULL;     /* tmp pointer to the client data */
2674 #if FS_STATS_DETAILED
2675     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2676     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2677     struct timeval elapsedTime; /* Transfer time */
2678
2679     /*
2680      * Set our stats pointer, remember when the RPC operation started, and
2681      * tally the operation.
2682      */
2683     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2684     FS_LOCK;
2685     (opP->numOps)++;
2686     FS_UNLOCK;
2687     FT_GetTimeOfDay(&opStartTime, 0);
2688 #endif /* FS_STATS_DETAILED */
2689
2690     ViceLog(1, ("SAFS_BulkStatus\n"));
2691     FS_LOCK;
2692     AFSCallStats.TotalCalls++;
2693     FS_UNLOCK;
2694     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2695     if (nfiles <= 0) {          /* Sanity check */
2696         errorCode = EINVAL;
2697         goto Audit_and_Return;
2698     }
2699
2700     /* allocate space for return output parameters */
2701     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2702         malloc(nfiles * sizeof(struct AFSFetchStatus));
2703     if (!OutStats->AFSBulkStats_val) {
2704         ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2705     }
2706     OutStats->AFSBulkStats_len = nfiles;
2707     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2708         malloc(nfiles * sizeof(struct AFSCallBack));
2709     if (!CallBacks->AFSCBs_val) {
2710         ViceLogThenPanic(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2711     }
2712     CallBacks->AFSCBs_len = nfiles;
2713
2714     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2715         goto Bad_BulkStatus;
2716
2717     tfid = Fids->AFSCBFids_val;
2718     for (i = 0; i < nfiles; i++, tfid++) {
2719         /*
2720          * Get volume/vnode for the fetched file; caller's rights to it
2721          * are also returned
2722          */
2723         if ((errorCode =
2724              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2725                               &parentwhentargetnotdir, &client, READ_LOCK,
2726                               &rights, &anyrights)))
2727             goto Bad_BulkStatus;
2728         /* set volume synchronization information, but only once per call */
2729         if (i == 0)
2730             SetVolumeSync(Sync, volptr);
2731
2732         /* Are we allowed to fetch Fid's status? */
2733         if (targetptr->disk.type != vDirectory) {
2734             if ((errorCode =
2735                  Check_PermissionRights(targetptr, client, rights,
2736                                         CHK_FETCHSTATUS, 0))) {
2737                 if (rx_GetCallAbortCode(acall) == errorCode)
2738                     rx_SetCallAbortCode(acall, 0);
2739                 goto Bad_BulkStatus;
2740             }
2741         }
2742
2743         /* set OutStatus From the Fid  */
2744         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2745                   anyrights, parentwhentargetnotdir);
2746
2747         /* If a r/w volume, also set the CallBack state */
2748         if (VolumeWriteable(volptr))
2749             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2750                               &CallBacks->AFSCBs_val[i]);
2751         else {
2752             struct AFSFid myFid;
2753             memset(&myFid, 0, sizeof(struct AFSFid));
2754             myFid.Volume = tfid->Volume;
2755             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2756                               &CallBacks->AFSCBs_val[i]);
2757         }
2758
2759         /* put back the file ID and volume */
2760         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2761                                volptr, &client);
2762         parentwhentargetnotdir = (Vnode *) 0;
2763         targetptr = (Vnode *) 0;
2764         volptr = (Volume *) 0;
2765         client = (struct client *)0;
2766     }
2767
2768   Bad_BulkStatus:
2769     /* Update and store volume/vnode and parent vnodes back */
2770     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2771                            volptr, &client);
2772     errorCode = CallPostamble(tcon, errorCode, thost);
2773
2774     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2775
2776 #if FS_STATS_DETAILED
2777     FT_GetTimeOfDay(&opStopTime, 0);
2778     if (errorCode == 0) {
2779         FS_LOCK;
2780         (opP->numSuccesses)++;
2781         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2782         fs_stats_AddTo((opP->sumTime), elapsedTime);
2783         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2784         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2785             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2786         }
2787         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2788             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2789         }
2790         FS_UNLOCK;
2791     }
2792 #endif /* FS_STATS_DETAILED */
2793
2794   Audit_and_Return:
2795     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode));
2796     osi_auditU(acall, BulkFetchStatusEvent, errorCode,
2797                AUD_ID, t_client ? t_client->ViceId : 0,
2798                AUD_FIDS, Fids, AUD_END);
2799     return errorCode;
2800
2801 }                               /*SRXAFS_BulkStatus */
2802
2803
2804 afs_int32
2805 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2806                         struct AFSBulkStats * OutStats,
2807                         struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2808 {
2809     int i;
2810     afs_int32 nfiles;
2811     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2812     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2813     Error errorCode = 0;                /* return code to caller */
2814     Volume *volptr = 0;         /* pointer to the volume */
2815     struct client *client = 0;  /* pointer to the client data */
2816     afs_int32 rights, anyrights;        /* rights for this and any user */
2817     struct AFSFid *tfid;        /* file id we're dealing with now */
2818     struct rx_connection *tcon;
2819     struct host *thost;
2820     struct client *t_client = NULL;     /* tmp ptr to client data */
2821     AFSFetchStatus *tstatus;
2822     int VolSync_set = 0;
2823 #if FS_STATS_DETAILED
2824     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2825     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2826     struct timeval elapsedTime; /* Transfer time */
2827
2828     /*
2829      * Set our stats pointer, remember when the RPC operation started, and
2830      * tally the operation.
2831      */
2832     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2833     FS_LOCK;
2834     (opP->numOps)++;
2835     FS_UNLOCK;
2836     FT_GetTimeOfDay(&opStartTime, 0);
2837 #endif /* FS_STATS_DETAILED */
2838
2839     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2840     FS_LOCK;
2841     AFSCallStats.TotalCalls++;
2842     FS_UNLOCK;
2843     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2844     if (nfiles <= 0) {          /* Sanity check */
2845         errorCode = EINVAL;
2846         goto Audit_and_Return;
2847     }
2848
2849     /* allocate space for return output parameters */
2850     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2851         malloc(nfiles * sizeof(struct AFSFetchStatus));
2852     if (!OutStats->AFSBulkStats_val) {
2853         ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2854     }
2855     OutStats->AFSBulkStats_len = nfiles;
2856     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2857         malloc(nfiles * sizeof(struct AFSCallBack));
2858     if (!CallBacks->AFSCBs_val) {
2859         ViceLogThenPanic(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2860     }
2861     CallBacks->AFSCBs_len = nfiles;
2862
2863     /* Zero out return values to avoid leaking information on partial succes */
2864     memset(OutStats->AFSBulkStats_val, 0, nfiles * sizeof(struct AFSFetchStatus));
2865     memset(CallBacks->AFSCBs_val, 0, nfiles * sizeof(struct AFSCallBack));
2866     memset(Sync, 0, sizeof(*Sync));
2867
2868     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2869         goto Bad_InlineBulkStatus;
2870     }
2871
2872     tfid = Fids->AFSCBFids_val;
2873     for (i = 0; i < nfiles; i++, tfid++) {
2874         /*
2875          * Get volume/vnode for the fetched file; caller's rights to it
2876          * are also returned
2877          */
2878         if ((errorCode =
2879              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2880                               &parentwhentargetnotdir, &client, READ_LOCK,
2881                               &rights, &anyrights))) {
2882             tstatus = &OutStats->AFSBulkStats_val[i];
2883             tstatus->errorCode = errorCode;
2884             PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2885                              volptr, &client);
2886             parentwhentargetnotdir = (Vnode *) 0;
2887             targetptr = (Vnode *) 0;
2888             volptr = (Volume *) 0;
2889             client = (struct client *)0;
2890             continue;
2891         }
2892
2893         /* set volume synchronization information, but only once per call */
2894         if (!VolSync_set) {
2895             SetVolumeSync(Sync, volptr);
2896             VolSync_set = 1;
2897         }
2898
2899         /* Are we allowed to fetch Fid's status? */
2900         if (targetptr->disk.type != vDirectory) {
2901             if ((errorCode =
2902                  Check_PermissionRights(targetptr, client, rights,
2903                                         CHK_FETCHSTATUS, 0))) {
2904                 tstatus = &OutStats->AFSBulkStats_val[i];
2905                 tstatus->errorCode = errorCode;
2906                 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2907                                        (Vnode *) 0, volptr, &client);
2908                 parentwhentargetnotdir = (Vnode *) 0;
2909                 targetptr = (Vnode *) 0;
2910                 volptr = (Volume *) 0;
2911                 client = (struct client *)0;
2912                 continue;
2913             }
2914         }
2915
2916         /* set OutStatus From the Fid  */
2917         GetStatus(targetptr,
2918                   (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2919                   rights, anyrights, parentwhentargetnotdir);
2920
2921         /* If a r/w volume, also set the CallBack state */
2922         if (VolumeWriteable(volptr))
2923             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2924                               &CallBacks->AFSCBs_val[i]);
2925         else {
2926             struct AFSFid myFid;
2927             memset(&myFid, 0, sizeof(struct AFSFid));
2928             myFid.Volume = tfid->Volume;
2929             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2930                               &CallBacks->AFSCBs_val[i]);
2931         }
2932
2933         /* put back the file ID and volume */
2934         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2935                                volptr, &client);
2936         parentwhentargetnotdir = (Vnode *) 0;
2937         targetptr = (Vnode *) 0;
2938         volptr = (Volume *) 0;
2939         client = (struct client *)0;
2940     }
2941
2942   Bad_InlineBulkStatus:
2943     /* Update and store volume/vnode and parent vnodes back */
2944     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2945                            volptr, &client);
2946     errorCode = CallPostamble(tcon, errorCode, thost);
2947
2948     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2949
2950 #if FS_STATS_DETAILED
2951     FT_GetTimeOfDay(&opStopTime, 0);
2952     if (errorCode == 0) {
2953         FS_LOCK;
2954         (opP->numSuccesses)++;
2955         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2956         fs_stats_AddTo((opP->sumTime), elapsedTime);
2957         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2958         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2959             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2960         }
2961         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2962             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2963         }
2964         FS_UNLOCK;
2965     }
2966 #endif /* FS_STATS_DETAILED */
2967
2968   Audit_and_Return:
2969     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode));
2970     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode,
2971                AUD_ID, t_client ? t_client->ViceId : 0,
2972                AUD_FIDS, Fids, AUD_END);
2973     return 0;
2974
2975 }                               /*SRXAFS_InlineBulkStatus */
2976
2977
2978 afs_int32
2979 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2980                    struct AFSFetchStatus * OutStatus,
2981                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2982 {
2983     afs_int32 code;
2984     struct rx_connection *tcon;
2985     struct host *thost;
2986     struct client *t_client = NULL;     /* tmp ptr to client data */
2987 #if FS_STATS_DETAILED
2988     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2989     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2990     struct timeval elapsedTime; /* Transfer time */
2991
2992     /*
2993      * Set our stats pointer, remember when the RPC operation started, and
2994      * tally the operation.
2995      */
2996     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2997     FS_LOCK;
2998     (opP->numOps)++;
2999     FS_UNLOCK;
3000     FT_GetTimeOfDay(&opStartTime, 0);
3001 #endif /* FS_STATS_DETAILED */
3002
3003     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3004         goto Bad_FetchStatus;
3005
3006     code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
3007
3008   Bad_FetchStatus:
3009     code = CallPostamble(tcon, code, thost);
3010
3011     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3012
3013 #if FS_STATS_DETAILED
3014     FT_GetTimeOfDay(&opStopTime, 0);
3015     if (code == 0) {
3016         FS_LOCK;
3017         (opP->numSuccesses)++;
3018         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3019         fs_stats_AddTo((opP->sumTime), elapsedTime);
3020         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3021         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3022             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3023         }
3024         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3025             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3026         }
3027         FS_UNLOCK;
3028     }
3029 #endif /* FS_STATS_DETAILED */
3030
3031     osi_auditU(acall, FetchStatusEvent, code,
3032                AUD_ID, t_client ? t_client->ViceId : 0,
3033                AUD_FID, Fid, AUD_END);
3034     return code;
3035
3036 }                               /*SRXAFS_FetchStatus */
3037
3038 static
3039   afs_int32
3040 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
3041                    struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
3042                    afs_fsize_t Length, afs_fsize_t FileLength,
3043                    struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3044 {
3045     Vnode *targetptr = 0;       /* pointer to input fid */
3046     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3047     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
3048     Error errorCode = 0;                /* return code for caller */
3049     Error fileCode = 0;         /* return code from vol package */
3050     Volume *volptr = 0;         /* pointer to the volume header */
3051     struct client *client = 0;  /* pointer to client structure */
3052     afs_int32 rights, anyrights;        /* rights for this and any user */
3053     struct client *t_client = NULL;     /* tmp ptr to client data */
3054     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3055     struct rx_connection *tcon;
3056     struct host *thost;
3057 #if FS_STATS_DETAILED
3058     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3059     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
3060     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3061     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
3062     struct timeval elapsedTime; /* Transfer time */
3063     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
3064     afs_sfsize_t bytesXferred;  /* # bytes actually xfer */
3065     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
3066
3067     /*
3068      * Set our stats pointers, remember when the RPC operation started, and
3069      * tally the operation.
3070      */
3071     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
3072     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
3073     FS_LOCK;
3074     (opP->numOps)++;
3075     FS_UNLOCK;
3076     ViceLog(1,
3077             ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
3078              Fid->Unique));
3079     FT_GetTimeOfDay(&opStartTime, 0);
3080 #endif /* FS_STATS_DETAILED */
3081
3082     FS_LOCK;
3083     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
3084     FS_UNLOCK;
3085     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3086         goto Bad_StoreData;
3087
3088     /* Get ptr to client data for user Id for logging */
3089     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3090     logHostAddr.s_addr = rxr_HostOf(tcon);
3091     ViceLog(5,
3092             ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
3093              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3094              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3095
3096     /*
3097      * Get associated volume/vnode for the stored file; caller's rights
3098      * are also returned
3099      */
3100     if ((errorCode =
3101          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
3102                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3103                           &rights, &anyrights))) {
3104         goto Bad_StoreData;
3105     }
3106
3107     /* set volume synchronization information */
3108     SetVolumeSync(Sync, volptr);
3109
3110     if ((targetptr->disk.type == vSymlink)) {
3111         /* Should we return a better error code here??? */
3112         errorCode = EISDIR;
3113         goto Bad_StoreData;
3114     }
3115
3116     /* Check if we're allowed to store the data */
3117     if ((errorCode =
3118          Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
3119                                 InStatus))) {
3120         goto Bad_StoreData;
3121     }
3122
3123     /*
3124      * Drop the read lock on the parent directory after saving the parent
3125      * vnode information we need to pass to GetStatus
3126      */
3127     if (parentwhentargetnotdir != NULL) {
3128         tparentwhentargetnotdir = *parentwhentargetnotdir;
3129         VPutVnode(&fileCode, parentwhentargetnotdir);
3130         osi_Assert(!fileCode || (fileCode == VSALVAGE));
3131         parentwhentargetnotdir = NULL;
3132     }
3133 #if FS_STATS_DETAILED
3134     /*
3135      * Remember when the data transfer started.
3136      */
3137     FT_GetTimeOfDay(&xferStartTime, 0);
3138 #endif /* FS_STATS_DETAILED */
3139
3140     /* Do the actual storing of the data */
3141 #if FS_STATS_DETAILED
3142     errorCode =
3143         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3144                           FileLength, (InStatus->Mask & AFS_FSYNC),
3145                           &bytesToXfer, &bytesXferred);
3146 #else
3147     errorCode =
3148         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3149                           FileLength, (InStatus->Mask & AFS_FSYNC));
3150     if (errorCode && (!targetptr->changed_newTime))
3151         goto Bad_StoreData;
3152 #endif /* FS_STATS_DETAILED */
3153 #if FS_STATS_DETAILED
3154     /*
3155      * At this point, the data transfer is done, for good or ill.  Remember
3156      * when the transfer ended, bump the number of successes/failures, and
3157      * integrate the transfer size and elapsed time into the stats.  If the
3158      * operation failed, we jump to the appropriate point.
3159      */
3160     FT_GetTimeOfDay(&xferStopTime, 0);
3161     FS_LOCK;
3162     (xferP->numXfers)++;
3163     if (!errorCode) {
3164         (xferP->numSuccesses)++;
3165
3166         /*
3167          * Bump the xfer sum by the number of bytes actually sent, NOT the
3168          * target number.
3169          */
3170         tot_bytesXferred += bytesXferred;
3171         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3172         tot_bytesXferred &= 0x3FF;
3173         if (bytesXferred < xferP->minBytes)
3174             xferP->minBytes = bytesXferred;
3175         if (bytesXferred > xferP->maxBytes)
3176             xferP->maxBytes = bytesXferred;
3177
3178         /*
3179          * Tally the size of the object.  Note: we tally the actual size,
3180          * NOT the number of bytes that made it out over the wire.
3181          */
3182         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3183             (xferP->count[0])++;
3184         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3185             (xferP->count[1])++;
3186         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3187             (xferP->count[2])++;
3188         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3189             (xferP->count[3])++;
3190         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3191             (xferP->count[4])++;
3192         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3193             (xferP->count[5])++;
3194         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3195             (xferP->count[6])++;
3196         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3197             (xferP->count[7])++;
3198         else
3199             (xferP->count[8])++;
3200
3201         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3202         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3203         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3204         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3205             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3206         }
3207         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3208             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3209         }
3210     }
3211     FS_UNLOCK;
3212     /*
3213      * Finally, go off to tell our caller the bad news in case the
3214      * store failed.
3215      */
3216     if (errorCode && (!targetptr->changed_newTime))
3217         goto Bad_StoreData;
3218 #endif /* FS_STATS_DETAILED */
3219
3220     /* Update the status of the target's vnode */
3221     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3222                              targetptr, volptr, 0);
3223
3224     /* Get the updated File's status back to the caller */
3225     GetStatus(targetptr, OutStatus, rights, anyrights,
3226               &tparentwhentargetnotdir);
3227
3228   Bad_StoreData:
3229     /* Update and store volume/vnode and parent vnodes back */
3230     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3231                            volptr, &client);
3232     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3233
3234     errorCode = CallPostamble(tcon, errorCode, thost);
3235
3236 #if FS_STATS_DETAILED
3237     FT_GetTimeOfDay(&opStopTime, 0);
3238     if (errorCode == 0) {
3239         FS_LOCK;
3240         (opP->numSuccesses)++;
3241         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3242         fs_stats_AddTo((opP->sumTime), elapsedTime);
3243         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3244         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3245             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3246         }
3247         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3248             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3249         }
3250         FS_UNLOCK;
3251     }
3252 #endif /* FS_STATS_DETAILED */
3253     osi_auditU(acall, StoreDataEvent, errorCode,
3254                AUD_ID, t_client ? t_client->ViceId : 0,
3255                AUD_FID, Fid, AUD_END);
3256     return (errorCode);
3257 }                               /*common_StoreData64 */
3258
3259 afs_int32
3260 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3261                  struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3262                  afs_uint32 Length, afs_uint32 FileLength,
3263                  struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3264 {
3265     if (FileLength > 0x7fffffff || Pos > 0x7fffffff ||
3266         (0x7fffffff - Pos) < Length)
3267         return EFBIG;
3268
3269     return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3270                               OutStatus, Sync);
3271 }                               /*SRXAFS_StoreData */
3272
3273 afs_int32
3274 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3275                    struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3276                    afs_uint64 Length, afs_uint64 FileLength,
3277                    struct AFSFetchStatus * OutStatus,
3278                    struct AFSVolSync * Sync)
3279 {
3280     int code;
3281     afs_fsize_t tPos;
3282     afs_fsize_t tLength;
3283     afs_fsize_t tFileLength;
3284
3285     tPos = (afs_fsize_t) Pos;
3286     tLength = (afs_fsize_t) Length;
3287     tFileLength = (afs_fsize_t) FileLength;
3288
3289     code =
3290         common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3291                            OutStatus, Sync);
3292     return code;
3293 }
3294
3295 afs_int32
3296 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3297                 struct AFSOpaque * AccessList,
3298                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3299 {
3300     Vnode *targetptr = 0;       /* pointer to input fid */
3301     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3302     Error errorCode = 0;                /* return code for caller */
3303     struct AFSStoreStatus InStatus;     /* Input status for fid */
3304     Volume *volptr = 0;         /* pointer to the volume header */
3305     struct client *client = 0;  /* pointer to client structure */
3306     afs_int32 rights, anyrights;        /* rights for this and any user */
3307     struct rx_connection *tcon;
3308     struct host *thost;
3309     struct client *t_client = NULL;     /* tmp ptr to client data */
3310     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3311 #if FS_STATS_DETAILED
3312     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3313     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3314     struct timeval elapsedTime; /* Transfer time */
3315
3316     /*
3317      * Set our stats pointer, remember when the RPC operation started, and
3318      * tally the operation.
3319      */
3320     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3321     FS_LOCK;
3322     (opP->numOps)++;
3323     FS_UNLOCK;
3324     FT_GetTimeOfDay(&opStartTime, 0);
3325 #endif /* FS_STATS_DETAILED */
3326     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3327         goto Bad_StoreACL;
3328
3329     /* Get ptr to client data for user Id for logging */
3330     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3331     logHostAddr.s_addr = rxr_HostOf(tcon);
3332     ViceLog(1,
3333             ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3334              Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3335              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3336     FS_LOCK;
3337     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3338     FS_UNLOCK;
3339     InStatus.Mask = 0;          /* not storing any status */
3340
3341     /*
3342      * Get associated volume/vnode for the target dir; caller's rights
3343      * are also returned.
3344      */
3345     if ((errorCode =
3346          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3347                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3348                           &rights, &anyrights))) {
3349         goto Bad_StoreACL;
3350     }
3351
3352     /* set volume synchronization information */
3353     SetVolumeSync(Sync, volptr);
3354
3355     /* Check if we have permission to change the dir's ACL */
3356     if ((errorCode =
3357          Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3358                                 &InStatus))) {
3359         goto Bad_StoreACL;
3360     }
3361
3362     /* Build and store the new Access List for the dir */
3363     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3364         goto Bad_StoreACL;
3365     }
3366
3367     targetptr->changed_newTime = 1;     /* status change of directory */
3368
3369     /* convert the write lock to a read lock before breaking callbacks */
3370     VVnodeWriteToRead(&errorCode, targetptr);
3371     osi_Assert(!errorCode || errorCode == VSALVAGE);
3372
3373     /* break call backs on the directory  */
3374     BreakCallBack(client->host, Fid, 0);
3375
3376     /* Get the updated dir's status back to the caller */
3377     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3378
3379   Bad_StoreACL:
3380     /* Update and store volume/vnode and parent vnodes back */
3381     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3382                      volptr, &client);
3383     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3384     errorCode = CallPostamble(tcon, errorCode, thost);
3385
3386 #if FS_STATS_DETAILED
3387     FT_GetTimeOfDay(&opStopTime, 0);
3388     if (errorCode == 0) {
3389         FS_LOCK;
3390         (opP->numSuccesses)++;
3391         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3392         fs_stats_AddTo((opP->sumTime), elapsedTime);
3393         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3394         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3395             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3396         }
3397         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3398             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3399         }
3400         FS_UNLOCK;
3401     }
3402 #endif /* FS_STATS_DETAILED */
3403
3404     osi_auditU(acall, StoreACLEvent, errorCode,
3405                AUD_ID, t_client ? t_client->ViceId : 0,
3406                AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3407     return errorCode;
3408
3409 }                               /*SRXAFS_StoreACL */
3410
3411
3412 /*
3413  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3414  * should be merged when possible.
3415  */
3416 static afs_int32
3417 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3418                   struct AFSStoreStatus *InStatus,
3419                   struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3420 {
3421     Vnode *targetptr = 0;       /* pointer to input fid */
3422     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3423     Error errorCode = 0;                /* return code for caller */
3424     Volume *volptr = 0;         /* pointer to the volume header */
3425     struct client *client = 0;  /* pointer to client structure */
3426     afs_int32 rights, anyrights;        /* rights for this and any user */
3427     struct client *t_client = NULL;     /* tmp ptr to client data */
3428     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3429     struct rx_connection *tcon = rx_ConnectionOf(acall);
3430
3431     /* Get ptr to client data for user Id for logging */
3432     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3433     logHostAddr.s_addr = rxr_HostOf(tcon);
3434     ViceLog(1,
3435             ("SAFS_StoreStatus,  Fid    = %u.%u.%u, Host %s:%d, Id %d\n",
3436              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3437              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3438     FS_LOCK;
3439     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3440     FS_UNLOCK;
3441     /*
3442      * Get volume/vnode for the target file; caller's rights to it are
3443      * also returned
3444      */
3445     if ((errorCode =
3446          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3447                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3448                           &rights, &anyrights))) {
3449         goto Bad_StoreStatus;
3450     }
3451
3452     /* set volume synchronization information */
3453     SetVolumeSync(Sync, volptr);
3454
3455     /* Check if the caller has proper permissions to store status to Fid */
3456     if ((errorCode =
3457          Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3458                                 InStatus))) {