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