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