rx: Make statistics interface use Atomics
[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/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             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                 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     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         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         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         pthread_cond_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         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         assert(!fileCode || (fileCode == VSALVAGE));
818     }
819     if (targetptr) {
820         VPutVnode(&fileCode, targetptr);
821         assert(!fileCode || (fileCode == VSALVAGE));
822     }
823     if (parentptr) {
824         VPutVnode(&fileCode, parentptr);
825         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     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     assert(!rc);
1253     IH_RELEASE(targetptr->handle);
1254
1255     rc = FDH_SYNC(newFdP);
1256     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     /*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         assert(0);
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         assert(0);
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         assert(0);
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         assert(0);
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             assert(0);
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         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 #ifdef AFS_64BIT_ENV
2372     tPos = (afs_sfsize_t) Pos;
2373     tLen = (afs_sfsize_t) Len;
2374 #else /* AFS_64BIT_ENV */
2375     if (Pos.high || Len.high)
2376         return EFBIG;
2377     tPos = Pos.low;
2378     tLen = Len.low;
2379 #endif /* AFS_64BIT_ENV */
2380
2381     code =
2382         common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2383                            1);
2384     return code;
2385 }
2386
2387 afs_int32
2388 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2389                 struct AFSOpaque * AccessList,
2390                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2391 {
2392     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2393     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2394     Error errorCode = 0;                /* return error code to caller */
2395     Volume *volptr = 0;         /* pointer to the volume */
2396     struct client *client = 0;  /* pointer to the client data */
2397     afs_int32 rights, anyrights;        /* rights for this and any user */
2398     struct rx_connection *tcon = rx_ConnectionOf(acall);
2399     struct host *thost;
2400     struct client *t_client = NULL;     /* tmp ptr to client data */
2401     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2402 #if FS_STATS_DETAILED
2403     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2404     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2405     struct timeval elapsedTime; /* Transfer time */
2406
2407     /*
2408      * Set our stats pointer, remember when the RPC operation started, and
2409      * tally the operation.
2410      */
2411     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2412     FS_LOCK;
2413     (opP->numOps)++;
2414     FS_UNLOCK;
2415     FT_GetTimeOfDay(&opStartTime, 0);
2416 #endif /* FS_STATS_DETAILED */
2417
2418     ViceLog(1,
2419             ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2420              Fid->Unique));
2421     FS_LOCK;
2422     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2423     FS_UNLOCK;
2424     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2425         goto Bad_FetchACL;
2426
2427     /* Get ptr to client data for user Id for logging */
2428     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2429     logHostAddr.s_addr = rxr_HostOf(tcon);
2430     ViceLog(5,
2431             ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2432              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2433              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2434
2435     AccessList->AFSOpaque_len = 0;
2436     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2437     if (!AccessList->AFSOpaque_val) {
2438         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2439         assert(0);
2440     }
2441
2442     /*
2443      * Get volume/vnode for the fetched file; caller's access rights to it
2444      * are also returned
2445      */
2446     if ((errorCode =
2447          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2448                           &parentwhentargetnotdir, &client, READ_LOCK,
2449                           &rights, &anyrights)))
2450         goto Bad_FetchACL;
2451
2452     SetVolumeSync(Sync, volptr);
2453
2454     /* Check whether we have permission to fetch the ACL */
2455     if ((errorCode =
2456          Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2457         goto Bad_FetchACL;
2458
2459     /* Get the Access List from the dir's vnode */
2460     if ((errorCode =
2461          RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2462         goto Bad_FetchACL;
2463
2464     /* Get OutStatus back From the target Vnode  */
2465     GetStatus(targetptr, OutStatus, rights, anyrights,
2466               parentwhentargetnotdir);
2467
2468   Bad_FetchACL:
2469     /* Update and store volume/vnode and parent vnodes back */
2470     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2471                            volptr, &client);
2472     ViceLog(2,
2473             ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2474              AccessList->AFSOpaque_val));
2475     errorCode = CallPostamble(tcon, errorCode, thost);
2476
2477 #if FS_STATS_DETAILED
2478     FT_GetTimeOfDay(&opStopTime, 0);
2479     if (errorCode == 0) {
2480         FS_LOCK;
2481         (opP->numSuccesses)++;
2482         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2483         fs_stats_AddTo((opP->sumTime), elapsedTime);
2484         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2485         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2486             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2487         }
2488         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2489             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2490         }
2491         FS_UNLOCK;
2492     }
2493 #endif /* FS_STATS_DETAILED */
2494
2495     osi_auditU(acall, FetchACLEvent, errorCode,
2496                AUD_ID, t_client ? t_client->ViceId : 0,
2497                AUD_FID, Fid,
2498                AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2499     return errorCode;
2500 }                               /*SRXAFS_FetchACL */
2501
2502
2503 /*
2504  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2505  * merged into it when possible.
2506  */
2507 static
2508   afs_int32
2509 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2510                   struct AFSFetchStatus *OutStatus,
2511                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2512 {
2513     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2514     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2515     Error errorCode = 0;                /* return code to caller */
2516     Volume *volptr = 0;         /* pointer to the volume */
2517     struct client *client = 0;  /* pointer to the client data */
2518     afs_int32 rights, anyrights;        /* rights for this and any user */
2519     struct client *t_client = NULL;     /* tmp ptr to client data */
2520     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2521     struct rx_connection *tcon = rx_ConnectionOf(acall);
2522
2523     /* Get ptr to client data for user Id for logging */
2524     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2525     logHostAddr.s_addr = rxr_HostOf(tcon);
2526     ViceLog(1,
2527             ("SAFS_FetchStatus,  Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2528              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2529              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2530     FS_LOCK;
2531     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2532     FS_UNLOCK;
2533     /*
2534      * Get volume/vnode for the fetched file; caller's rights to it are
2535      * also returned
2536      */
2537     if ((errorCode =
2538          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2539                           &parentwhentargetnotdir, &client, READ_LOCK,
2540                           &rights, &anyrights)))
2541         goto Bad_FetchStatus;
2542
2543     /* set volume synchronization information */
2544     SetVolumeSync(Sync, volptr);
2545
2546     /* Are we allowed to fetch Fid's status? */
2547     if (targetptr->disk.type != vDirectory) {
2548         if ((errorCode =
2549              Check_PermissionRights(targetptr, client, rights,
2550                                     CHK_FETCHSTATUS, 0))) {
2551             if (rx_GetCallAbortCode(acall) == errorCode)
2552                 rx_SetCallAbortCode(acall, 0);
2553             goto Bad_FetchStatus;
2554         }
2555     }
2556
2557     /* set OutStatus From the Fid  */
2558     GetStatus(targetptr, OutStatus, rights, anyrights,
2559               parentwhentargetnotdir);
2560
2561     /* If a r/w volume, also set the CallBack state */
2562     if (VolumeWriteable(volptr))
2563         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2564     else {
2565         struct AFSFid myFid;
2566         memset(&myFid, 0, sizeof(struct AFSFid));
2567         myFid.Volume = Fid->Volume;
2568         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2569     }
2570
2571   Bad_FetchStatus:
2572     /* Update and store volume/vnode and parent vnodes back */
2573     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2574                            volptr, &client);
2575     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2576     return errorCode;
2577
2578 }                               /*SAFSS_FetchStatus */
2579
2580
2581 afs_int32
2582 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2583                   struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2584                   struct AFSVolSync * Sync)
2585 {
2586     int i;
2587     afs_int32 nfiles;
2588     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2589     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2590     Error errorCode = 0;                /* return code to caller */
2591     Volume *volptr = 0;         /* pointer to the volume */
2592     struct client *client = 0;  /* pointer to the client data */
2593     afs_int32 rights, anyrights;        /* rights for this and any user */
2594     struct AFSFid *tfid;        /* file id we're dealing with now */
2595     struct rx_connection *tcon = rx_ConnectionOf(acall);
2596     struct host *thost;
2597     struct client *t_client = NULL;     /* tmp pointer to the client data */
2598 #if FS_STATS_DETAILED
2599     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2600     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2601     struct timeval elapsedTime; /* Transfer time */
2602
2603     /*
2604      * Set our stats pointer, remember when the RPC operation started, and
2605      * tally the operation.
2606      */
2607     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2608     FS_LOCK;
2609     (opP->numOps)++;
2610     FS_UNLOCK;
2611     FT_GetTimeOfDay(&opStartTime, 0);
2612 #endif /* FS_STATS_DETAILED */
2613
2614     ViceLog(1, ("SAFS_BulkStatus\n"));
2615     FS_LOCK;
2616     AFSCallStats.TotalCalls++;
2617     FS_UNLOCK;
2618     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2619     if (nfiles <= 0) {          /* Sanity check */
2620         errorCode = EINVAL;
2621         goto Audit_and_Return;
2622     }
2623
2624     /* allocate space for return output parameters */
2625     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2626         malloc(nfiles * sizeof(struct AFSFetchStatus));
2627     if (!OutStats->AFSBulkStats_val) {
2628         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2629         assert(0);
2630     }
2631     OutStats->AFSBulkStats_len = nfiles;
2632     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2633         malloc(nfiles * sizeof(struct AFSCallBack));
2634     if (!CallBacks->AFSCBs_val) {
2635         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2636         assert(0);
2637     }
2638     CallBacks->AFSCBs_len = nfiles;
2639
2640     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2641         goto Bad_BulkStatus;
2642
2643     tfid = Fids->AFSCBFids_val;
2644     for (i = 0; i < nfiles; i++, tfid++) {
2645         /*
2646          * Get volume/vnode for the fetched file; caller's rights to it
2647          * are also returned
2648          */
2649         if ((errorCode =
2650              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2651                               &parentwhentargetnotdir, &client, READ_LOCK,
2652                               &rights, &anyrights)))
2653             goto Bad_BulkStatus;
2654         /* set volume synchronization information, but only once per call */
2655         if (i == 0)
2656             SetVolumeSync(Sync, volptr);
2657
2658         /* Are we allowed to fetch Fid's status? */
2659         if (targetptr->disk.type != vDirectory) {
2660             if ((errorCode =
2661                  Check_PermissionRights(targetptr, client, rights,
2662                                         CHK_FETCHSTATUS, 0))) {
2663                 if (rx_GetCallAbortCode(acall) == errorCode)
2664                     rx_SetCallAbortCode(acall, 0);
2665                 goto Bad_BulkStatus;
2666             }
2667         }
2668
2669         /* set OutStatus From the Fid  */
2670         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2671                   anyrights, parentwhentargetnotdir);
2672
2673         /* If a r/w volume, also set the CallBack state */
2674         if (VolumeWriteable(volptr))
2675             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2676                               &CallBacks->AFSCBs_val[i]);
2677         else {
2678             struct AFSFid myFid;
2679             memset(&myFid, 0, sizeof(struct AFSFid));
2680             myFid.Volume = tfid->Volume;
2681             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2682                               &CallBacks->AFSCBs_val[i]);
2683         }
2684
2685         /* put back the file ID and volume */
2686         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2687                                volptr, &client);
2688         parentwhentargetnotdir = (Vnode *) 0;
2689         targetptr = (Vnode *) 0;
2690         volptr = (Volume *) 0;
2691         client = (struct client *)0;
2692     }
2693
2694   Bad_BulkStatus:
2695     /* Update and store volume/vnode and parent vnodes back */
2696     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2697                            volptr, &client);
2698     errorCode = CallPostamble(tcon, errorCode, thost);
2699
2700     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2701
2702 #if FS_STATS_DETAILED
2703     FT_GetTimeOfDay(&opStopTime, 0);
2704     if (errorCode == 0) {
2705         FS_LOCK;
2706         (opP->numSuccesses)++;
2707         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2708         fs_stats_AddTo((opP->sumTime), elapsedTime);
2709         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2710         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2711             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2712         }
2713         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2714             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2715         }
2716         FS_UNLOCK;
2717     }
2718 #endif /* FS_STATS_DETAILED */
2719
2720   Audit_and_Return:
2721     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode));
2722     osi_auditU(acall, BulkFetchStatusEvent, errorCode,
2723                AUD_ID, t_client ? t_client->ViceId : 0,
2724                AUD_FIDS, Fids, AUD_END);
2725     return errorCode;
2726
2727 }                               /*SRXAFS_BulkStatus */
2728
2729
2730 afs_int32
2731 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2732                         struct AFSBulkStats * OutStats,
2733                         struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2734 {
2735     int i;
2736     afs_int32 nfiles;
2737     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2738     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2739     Error errorCode = 0;                /* return code to caller */
2740     Volume *volptr = 0;         /* pointer to the volume */
2741     struct client *client = 0;  /* pointer to the client data */
2742     afs_int32 rights, anyrights;        /* rights for this and any user */
2743     struct AFSFid *tfid;        /* file id we're dealing with now */
2744     struct rx_connection *tcon;
2745     struct host *thost;
2746     struct client *t_client = NULL;     /* tmp ptr to client data */
2747     AFSFetchStatus *tstatus;
2748     int VolSync_set = 0;
2749 #if FS_STATS_DETAILED
2750     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2751     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2752     struct timeval elapsedTime; /* Transfer time */
2753
2754     /*
2755      * Set our stats pointer, remember when the RPC operation started, and
2756      * tally the operation.
2757      */
2758     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2759     FS_LOCK;
2760     (opP->numOps)++;
2761     FS_UNLOCK;
2762     FT_GetTimeOfDay(&opStartTime, 0);
2763 #endif /* FS_STATS_DETAILED */
2764
2765     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2766     FS_LOCK;
2767     AFSCallStats.TotalCalls++;
2768     FS_UNLOCK;
2769     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2770     if (nfiles <= 0) {          /* Sanity check */
2771         errorCode = EINVAL;
2772         goto Audit_and_Return;
2773     }
2774
2775     /* allocate space for return output parameters */
2776     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2777         malloc(nfiles * sizeof(struct AFSFetchStatus));
2778     if (!OutStats->AFSBulkStats_val) {
2779         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2780         assert(0);
2781     }
2782     OutStats->AFSBulkStats_len = nfiles;
2783     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2784         malloc(nfiles * sizeof(struct AFSCallBack));
2785     if (!CallBacks->AFSCBs_val) {
2786         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2787         assert(0);
2788     }
2789     CallBacks->AFSCBs_len = nfiles;
2790
2791     /* Zero out return values to avoid leaking information on partial succes */
2792     memset(OutStats->AFSBulkStats_val, 0, nfiles * sizeof(struct AFSFetchStatus));
2793     memset(CallBacks->AFSCBs_val, 0, nfiles * sizeof(struct AFSCallBack));
2794     memset(Sync, 0, sizeof(*Sync));
2795
2796     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2797         goto Bad_InlineBulkStatus;
2798     }
2799
2800     tfid = Fids->AFSCBFids_val;
2801     for (i = 0; i < nfiles; i++, tfid++) {
2802         /*
2803          * Get volume/vnode for the fetched file; caller's rights to it
2804          * are also returned
2805          */
2806         if ((errorCode =
2807              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2808                               &parentwhentargetnotdir, &client, READ_LOCK,
2809                               &rights, &anyrights))) {
2810             tstatus = &OutStats->AFSBulkStats_val[i];
2811             tstatus->errorCode = errorCode;
2812             PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2813                              volptr, &client);
2814             parentwhentargetnotdir = (Vnode *) 0;
2815             targetptr = (Vnode *) 0;
2816             volptr = (Volume *) 0;
2817             client = (struct client *)0;
2818             continue;
2819         }
2820
2821         /* set volume synchronization information, but only once per call */
2822         if (!VolSync_set) {
2823             SetVolumeSync(Sync, volptr);
2824             VolSync_set = 1;
2825         }
2826
2827         /* Are we allowed to fetch Fid's status? */
2828         if (targetptr->disk.type != vDirectory) {
2829             if ((errorCode =
2830                  Check_PermissionRights(targetptr, client, rights,
2831                                         CHK_FETCHSTATUS, 0))) {
2832                 tstatus = &OutStats->AFSBulkStats_val[i];
2833                 tstatus->errorCode = errorCode;
2834                 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2835                                        (Vnode *) 0, volptr, &client);
2836                 parentwhentargetnotdir = (Vnode *) 0;
2837                 targetptr = (Vnode *) 0;
2838                 volptr = (Volume *) 0;
2839                 client = (struct client *)0;
2840                 continue;
2841             }
2842         }
2843
2844         /* set OutStatus From the Fid  */
2845         GetStatus(targetptr,
2846                   (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2847                   rights, anyrights, parentwhentargetnotdir);
2848
2849         /* If a r/w volume, also set the CallBack state */
2850         if (VolumeWriteable(volptr))
2851             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2852                               &CallBacks->AFSCBs_val[i]);
2853         else {
2854             struct AFSFid myFid;
2855             memset(&myFid, 0, sizeof(struct AFSFid));
2856             myFid.Volume = tfid->Volume;
2857             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2858                               &CallBacks->AFSCBs_val[i]);
2859         }
2860
2861         /* put back the file ID and volume */
2862         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2863                                volptr, &client);
2864         parentwhentargetnotdir = (Vnode *) 0;
2865         targetptr = (Vnode *) 0;
2866         volptr = (Volume *) 0;
2867         client = (struct client *)0;
2868     }
2869
2870   Bad_InlineBulkStatus:
2871     /* Update and store volume/vnode and parent vnodes back */
2872     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2873                            volptr, &client);
2874     errorCode = CallPostamble(tcon, errorCode, thost);
2875
2876     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2877
2878 #if FS_STATS_DETAILED
2879     FT_GetTimeOfDay(&opStopTime, 0);
2880     if (errorCode == 0) {
2881         FS_LOCK;
2882         (opP->numSuccesses)++;
2883         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2884         fs_stats_AddTo((opP->sumTime), elapsedTime);
2885         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2886         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2887             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2888         }
2889         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2890             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2891         }
2892         FS_UNLOCK;
2893     }
2894 #endif /* FS_STATS_DETAILED */
2895
2896   Audit_and_Return:
2897     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode));
2898     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode,
2899                AUD_ID, t_client ? t_client->ViceId : 0,
2900                AUD_FIDS, Fids, AUD_END);
2901     return 0;
2902
2903 }                               /*SRXAFS_InlineBulkStatus */
2904
2905
2906 afs_int32
2907 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2908                    struct AFSFetchStatus * OutStatus,
2909                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2910 {
2911     afs_int32 code;
2912     struct rx_connection *tcon;
2913     struct host *thost;
2914     struct client *t_client = NULL;     /* tmp ptr to client data */
2915 #if FS_STATS_DETAILED
2916     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2917     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2918     struct timeval elapsedTime; /* Transfer time */
2919
2920     /*
2921      * Set our stats pointer, remember when the RPC operation started, and
2922      * tally the operation.
2923      */
2924     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2925     FS_LOCK;
2926     (opP->numOps)++;
2927     FS_UNLOCK;
2928     FT_GetTimeOfDay(&opStartTime, 0);
2929 #endif /* FS_STATS_DETAILED */
2930
2931     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2932         goto Bad_FetchStatus;
2933
2934     code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
2935
2936   Bad_FetchStatus:
2937     code = CallPostamble(tcon, code, thost);
2938
2939     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2940
2941 #if FS_STATS_DETAILED
2942     FT_GetTimeOfDay(&opStopTime, 0);
2943     if (code == 0) {
2944         FS_LOCK;
2945         (opP->numSuccesses)++;
2946         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2947         fs_stats_AddTo((opP->sumTime), elapsedTime);
2948         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2949         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2950             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2951         }
2952         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2953             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2954         }
2955         FS_UNLOCK;
2956     }
2957 #endif /* FS_STATS_DETAILED */
2958
2959     osi_auditU(acall, FetchStatusEvent, code,
2960                AUD_ID, t_client ? t_client->ViceId : 0,
2961                AUD_FID, Fid, AUD_END);
2962     return code;
2963
2964 }                               /*SRXAFS_FetchStatus */
2965
2966 static
2967   afs_int32
2968 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
2969                    struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
2970                    afs_fsize_t Length, afs_fsize_t FileLength,
2971                    struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
2972 {
2973     Vnode *targetptr = 0;       /* pointer to input fid */
2974     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
2975     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2976     Error errorCode = 0;                /* return code for caller */
2977     Error fileCode = 0;         /* return code from vol package */
2978     Volume *volptr = 0;         /* pointer to the volume header */
2979     struct client *client = 0;  /* pointer to client structure */
2980     afs_int32 rights, anyrights;        /* rights for this and any user */
2981     struct client *t_client = NULL;     /* tmp ptr to client data */
2982     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2983     struct rx_connection *tcon;
2984     struct host *thost;
2985 #if FS_STATS_DETAILED
2986     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2987     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2988     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2989     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2990     struct timeval elapsedTime; /* Transfer time */
2991     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2992     afs_sfsize_t bytesXferred;  /* # bytes actually xfer */
2993     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2994
2995     /*
2996      * Set our stats pointers, remember when the RPC operation started, and
2997      * tally the operation.
2998      */
2999     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
3000     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
3001     FS_LOCK;
3002     (opP->numOps)++;
3003     FS_UNLOCK;
3004     ViceLog(1,
3005             ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
3006              Fid->Unique));
3007     FT_GetTimeOfDay(&opStartTime, 0);
3008 #endif /* FS_STATS_DETAILED */
3009
3010     FS_LOCK;
3011     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
3012     FS_UNLOCK;
3013     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3014         goto Bad_StoreData;
3015
3016     /* Get ptr to client data for user Id for logging */
3017     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3018     logHostAddr.s_addr = rxr_HostOf(tcon);
3019     ViceLog(5,
3020             ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
3021              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3022              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3023
3024     /*
3025      * Get associated volume/vnode for the stored file; caller's rights
3026      * are also returned
3027      */
3028     if ((errorCode =
3029          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
3030                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3031                           &rights, &anyrights))) {
3032         goto Bad_StoreData;
3033     }
3034
3035     /* set volume synchronization information */
3036     SetVolumeSync(Sync, volptr);
3037
3038     if ((targetptr->disk.type == vSymlink)) {
3039         /* Should we return a better error code here??? */
3040         errorCode = EISDIR;
3041         goto Bad_StoreData;
3042     }
3043
3044     /* Check if we're allowed to store the data */
3045     if ((errorCode =
3046          Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
3047                                 InStatus))) {
3048         goto Bad_StoreData;
3049     }
3050
3051     /*
3052      * Drop the read lock on the parent directory after saving the parent
3053      * vnode information we need to pass to GetStatus
3054      */
3055     if (parentwhentargetnotdir != NULL) {
3056         tparentwhentargetnotdir = *parentwhentargetnotdir;
3057         VPutVnode(&fileCode, parentwhentargetnotdir);
3058         assert(!fileCode || (fileCode == VSALVAGE));
3059         parentwhentargetnotdir = NULL;
3060     }
3061 #if FS_STATS_DETAILED
3062     /*
3063      * Remember when the data transfer started.
3064      */
3065     FT_GetTimeOfDay(&xferStartTime, 0);
3066 #endif /* FS_STATS_DETAILED */
3067
3068     /* Do the actual storing of the data */
3069 #if FS_STATS_DETAILED
3070     errorCode =
3071         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3072                           FileLength, (InStatus->Mask & AFS_FSYNC),
3073                           &bytesToXfer, &bytesXferred);
3074 #else
3075     errorCode =
3076         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
3077                           FileLength, (InStatus->Mask & AFS_FSYNC));
3078     if (errorCode && (!targetptr->changed_newTime))
3079         goto Bad_StoreData;
3080 #endif /* FS_STATS_DETAILED */
3081 #if FS_STATS_DETAILED
3082     /*
3083      * At this point, the data transfer is done, for good or ill.  Remember
3084      * when the transfer ended, bump the number of successes/failures, and
3085      * integrate the transfer size and elapsed time into the stats.  If the
3086      * operation failed, we jump to the appropriate point.
3087      */
3088     FT_GetTimeOfDay(&xferStopTime, 0);
3089     FS_LOCK;
3090     (xferP->numXfers)++;
3091     if (!errorCode) {
3092         (xferP->numSuccesses)++;
3093
3094         /*
3095          * Bump the xfer sum by the number of bytes actually sent, NOT the
3096          * target number.
3097          */
3098         tot_bytesXferred += bytesXferred;
3099         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3100         tot_bytesXferred &= 0x3FF;
3101         if (bytesXferred < xferP->minBytes)
3102             xferP->minBytes = bytesXferred;
3103         if (bytesXferred > xferP->maxBytes)
3104             xferP->maxBytes = bytesXferred;
3105
3106         /*
3107          * Tally the size of the object.  Note: we tally the actual size,
3108          * NOT the number of bytes that made it out over the wire.
3109          */
3110         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3111             (xferP->count[0])++;
3112         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3113             (xferP->count[1])++;
3114         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3115             (xferP->count[2])++;
3116         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3117             (xferP->count[3])++;
3118         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3119             (xferP->count[4])++;
3120         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3121             (xferP->count[5])++;
3122         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3123             (xferP->count[6])++;
3124         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3125             (xferP->count[7])++;
3126         else
3127             (xferP->count[8])++;
3128
3129         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3130         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3131         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3132         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3133             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3134         }
3135         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3136             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3137         }
3138     }
3139     FS_UNLOCK;
3140     /*
3141      * Finally, go off to tell our caller the bad news in case the
3142      * store failed.
3143      */
3144     if (errorCode && (!targetptr->changed_newTime))
3145         goto Bad_StoreData;
3146 #endif /* FS_STATS_DETAILED */
3147
3148     /* Update the status of the target's vnode */
3149     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3150                              targetptr, volptr, 0);
3151
3152     /* Get the updated File's status back to the caller */
3153     GetStatus(targetptr, OutStatus, rights, anyrights,
3154               &tparentwhentargetnotdir);
3155
3156   Bad_StoreData:
3157     /* Update and store volume/vnode and parent vnodes back */
3158     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3159                            volptr, &client);
3160     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3161
3162     errorCode = CallPostamble(tcon, errorCode, thost);
3163
3164 #if FS_STATS_DETAILED
3165     FT_GetTimeOfDay(&opStopTime, 0);
3166     if (errorCode == 0) {
3167         FS_LOCK;
3168         (opP->numSuccesses)++;
3169         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3170         fs_stats_AddTo((opP->sumTime), elapsedTime);
3171         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3172         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3173             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3174         }
3175         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3176             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3177         }
3178         FS_UNLOCK;
3179     }
3180 #endif /* FS_STATS_DETAILED */
3181     osi_auditU(acall, StoreDataEvent, errorCode,
3182                AUD_ID, t_client ? t_client->ViceId : 0,
3183                AUD_FID, Fid, AUD_END);
3184     return (errorCode);
3185 }                               /*common_StoreData64 */
3186
3187 afs_int32
3188 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3189                  struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3190                  afs_uint32 Length, afs_uint32 FileLength,
3191                  struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3192 {
3193     if (FileLength > 0x7fffffff || Pos > 0x7fffffff ||
3194         (0x7fffffff - Pos) < Length)
3195         return EFBIG;
3196
3197     return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3198                               OutStatus, Sync);
3199 }                               /*SRXAFS_StoreData */
3200
3201 afs_int32
3202 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3203                    struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3204                    afs_uint64 Length, afs_uint64 FileLength,
3205                    struct AFSFetchStatus * OutStatus,
3206                    struct AFSVolSync * Sync)
3207 {
3208     int code;
3209     afs_fsize_t tPos;
3210     afs_fsize_t tLength;
3211     afs_fsize_t tFileLength;
3212
3213 #ifdef AFS_64BIT_ENV
3214     tPos = (afs_fsize_t) Pos;
3215     tLength = (afs_fsize_t) Length;
3216     tFileLength = (afs_fsize_t) FileLength;
3217 #else /* AFS_64BIT_ENV */
3218     if (FileLength.high)
3219         return EFBIG;
3220     tPos = Pos.low;
3221     tLength = Length.low;
3222     tFileLength = FileLength.low;
3223 #endif /* AFS_64BIT_ENV */
3224
3225     code =
3226         common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3227                            OutStatus, Sync);
3228     return code;
3229 }
3230
3231 afs_int32
3232 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3233                 struct AFSOpaque * AccessList,
3234                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3235 {
3236     Vnode *targetptr = 0;       /* pointer to input fid */
3237     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3238     Error errorCode = 0;                /* return code for caller */
3239     struct AFSStoreStatus InStatus;     /* Input status for fid */
3240     Volume *volptr = 0;         /* pointer to the volume header */
3241     struct client *client = 0;  /* pointer to client structure */
3242     afs_int32 rights, anyrights;        /* rights for this and any user */
3243     struct rx_connection *tcon;
3244     struct host *thost;
3245     struct client *t_client = NULL;     /* tmp ptr to client data */
3246     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3247 #if FS_STATS_DETAILED
3248     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3249     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3250     struct timeval elapsedTime; /* Transfer time */
3251
3252     /*
3253      * Set our stats pointer, remember when the RPC operation started, and
3254      * tally the operation.
3255      */
3256     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3257     FS_LOCK;
3258     (opP->numOps)++;
3259     FS_UNLOCK;
3260     FT_GetTimeOfDay(&opStartTime, 0);
3261 #endif /* FS_STATS_DETAILED */
3262     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3263         goto Bad_StoreACL;
3264
3265     /* Get ptr to client data for user Id for logging */
3266     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3267     logHostAddr.s_addr = rxr_HostOf(tcon);
3268     ViceLog(1,
3269             ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3270              Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3271              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3272     FS_LOCK;
3273     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3274     FS_UNLOCK;
3275     InStatus.Mask = 0;          /* not storing any status */
3276
3277     /*
3278      * Get associated volume/vnode for the target dir; caller's rights
3279      * are also returned.
3280      */
3281     if ((errorCode =
3282          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3283                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3284                           &rights, &anyrights))) {
3285         goto Bad_StoreACL;
3286     }
3287
3288     /* set volume synchronization information */
3289     SetVolumeSync(Sync, volptr);
3290
3291     /* Check if we have permission to change the dir's ACL */
3292     if ((errorCode =
3293          Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3294                                 &InStatus))) {
3295         goto Bad_StoreACL;
3296     }
3297
3298     /* Build and store the new Access List for the dir */
3299     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3300         goto Bad_StoreACL;
3301     }
3302
3303     targetptr->changed_newTime = 1;     /* status change of directory */
3304
3305     /* convert the write lock to a read lock before breaking callbacks */
3306     VVnodeWriteToRead(&errorCode, targetptr);
3307     assert(!errorCode || errorCode == VSALVAGE);
3308
3309     /* break call backs on the directory  */
3310     BreakCallBack(client->host, Fid, 0);
3311
3312     /* Get the updated dir's status back to the caller */
3313     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3314
3315   Bad_StoreACL:
3316     /* Update and store volume/vnode and parent vnodes back */
3317     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3318                      volptr, &client);
3319     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3320     errorCode = CallPostamble(tcon, errorCode, thost);
3321
3322 #if FS_STATS_DETAILED
3323     FT_GetTimeOfDay(&opStopTime, 0);
3324     if (errorCode == 0) {
3325         FS_LOCK;
3326         (opP->numSuccesses)++;
3327         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3328         fs_stats_AddTo((opP->sumTime), elapsedTime);
3329         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3330         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3331             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3332         }
3333         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3334             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3335         }
3336         FS_UNLOCK;
3337     }
3338 #endif /* FS_STATS_DETAILED */
3339
3340     osi_auditU(acall, StoreACLEvent, errorCode,
3341                AUD_ID, t_client ? t_client->ViceId : 0,
3342                AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3343     return errorCode;
3344
3345 }                               /*SRXAFS_StoreACL */
3346
3347
3348 /*
3349  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3350  * should be merged when possible.
3351  */
3352 static afs_int32
3353 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3354                   struct AFSStoreStatus *InStatus,
3355                   struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3356 {
3357     Vnode *targetptr = 0;       /* pointer to input fid */
3358     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3359     Error errorCode = 0;                /* return code for caller */
3360     Volume *volptr = 0;         /* pointer to the volume header */
3361     struct client *client = 0;  /* pointer to client structure */
3362     afs_int32 rights, anyrights;        /* rights for this and any user */
3363     struct client *t_client = NULL;     /* tmp ptr to client data */
3364     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3365     struct rx_connection *tcon = rx_ConnectionOf(acall);
3366
3367     /* Get ptr to client data for user Id for logging */
3368     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3369     logHostAddr.s_addr = rxr_HostOf(tcon);
3370     ViceLog(1,
3371             ("SAFS_StoreStatus,  Fid    = %u.%u.%u, Host %s:%d, Id %d\n",
3372              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3373              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3374     FS_LOCK;
3375     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3376     FS_UNLOCK;
3377     /*
3378      * Get volume/vnode for the target file; caller's rights to it are
3379      * also returned
3380      */
3381     if ((errorCode =
3382          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3383                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3384                           &rights, &anyrights))) {
3385         goto Bad_StoreStatus;
3386     }
3387
3388     /* set volume synchronization information */
3389     SetVolumeSync(Sync, volptr);
3390
3391     /* Check if the caller has proper permissions to store status to Fid */
3392     if ((errorCode =
3393          Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3394                                 InStatus))) {
3395         goto Bad_StoreStatus;
3396     }
3397     /*
3398      * Check for a symbolic link; we can't chmod these (otherwise could
3399      * change a symlink to a mt pt or vice versa)
3400      */
3401     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3402         errorCode = EINVAL;
3403         goto Bad_StoreStatus;
3404     }
3405
3406     /* Update the status of the target's vnode */
3407     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3408                              (parentwhentargetnotdir ? parentwhentargetnotdir
3409                               : targetptr), volptr, 0);
3410
3411     /* convert the write lock to a read lock before breaking callbacks */
3412     VVnodeWriteToRead(&errorCode, targetptr);
3413     assert(!errorCode || errorCode == VSALVAGE);
3414
3415     /* Break call backs on Fid */
3416     BreakCallBack(client->host, Fid, 0);
3417
3418     /* Return the updated status back to caller */
3419     GetStatus(targetptr, OutStatus, rights, anyrights,
3420               parentwhentargetnotdir);
3421
3422   Bad_StoreStatus:
3423     /* Update and store volume/vnode and parent vnodes back */
3424     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3425                      volptr, &client);
3426     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3427     return errorCode;
3428
3429 }                               /*SAFSS_StoreStatus */
3430
3431
3432 afs_int32
3433 SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
3434                    struct AFSStoreStatus * InStatus,
3435                    struct AFSFetchStatus * OutStatus,
3436                    struct AFSVolSync * Sync)
3437 {
3438     afs_int32 code;
3439     struct rx_connection *tcon;
3440     struct host *thost;
3441     struct client *t_client = NULL;     /* tmp ptr to client data */
3442 #if FS_STATS_DETAILED
3443     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3444     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3445     struct timeval elapsedTime; /* Transfer time */
3446
3447     /*
3448      * Set our stats pointer, remember when the RPC operation started, and
3449      * tally the operation.
3450      */
3451     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3452     FS_LOCK;
3453     (opP->numOps)++;
3454     FS_UNLOCK;
3455     FT_GetTimeOfDay(&opStartTime, 0);
3456 #endif /* FS_STATS_DETAILED */
3457
3458     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3459         goto Bad_StoreStatus;
3460
3461     code = SAFSS_StoreStatus(acall, Fid, InStatus, OutStatus, Sync);
3462
3463   Bad_StoreStatus:
3464     code = CallPostamble(tcon, code, thost);