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