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