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