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