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