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