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