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