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