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