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