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