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