09385c5acd629fd4b429c722976e62035bc8d179
[openafs.git] / src / viced / afsfileprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*  afs_fileprocs.c - Complete File Server request routines              */
11 /*                                                                       */
12 /*  Information Technology Center                                        */
13 /*  Carnegie Mellon University                                           */
14 /*                                                                       */
15 /*  Date: 8/10/88                                                        */
16 /*                                                                       */
17 /*  Function    - A set of routines to handle the various file Server    */
18 /*                  requests; these routines are invoked by rxgen.       */
19 /*                                                                       */
20 /* ********************************************************************** */
21
22 /* 
23  * in Check_PermissionRights, certain privileges are afforded to the owner 
24  * of the volume, or the owner of a file.  Are these considered "use of 
25  * privilege"? 
26  */
27
28 #include <afsconfig.h>
29 #include <afs/param.h>
30
31 RCSID
32     ("$Header$");
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #ifdef  AFS_SGI_ENV
38 #undef SHARED                   /* XXX */
39 #endif
40 #ifdef AFS_NT40_ENV
41 #include <fcntl.h>
42 #else
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50 #include <string.h>
51
52 #ifndef AFS_LINUX20_ENV
53 #include <net/if.h>
54 #include <netinet/if_ether.h>
55 #endif
56 #endif
57 #ifdef AFS_HPUX_ENV
58 /* included early because of name conflict on IOPEN */
59 #include <sys/inode.h>
60 #ifdef IOPEN
61 #undef IOPEN
62 #endif
63 #endif /* AFS_HPUX_ENV */
64 #include <afs/stds.h>
65 #include <rx/xdr.h>
66 #include <afs/nfs.h>
67 #include <afs/assert.h>
68 #include <lwp.h>
69 #include <lock.h>
70 #include <afs/afsint.h>
71 #include <afs/vldbint.h>
72 #include <afs/errors.h>
73 #include <afs/ihandle.h>
74 #include <afs/vnode.h>
75 #include <afs/volume.h>
76 #include <afs/ptclient.h>
77 #include <afs/ptuser.h>
78 #include <afs/prs_fs.h>
79 #include <afs/acl.h>
80 #include <rx/rx.h>
81 #include <rx/rx_globals.h>
82 #include <sys/stat.h>
83 #if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
84 #include <sys/map.h>
85 #endif
86 #if !defined(AFS_NT40_ENV)
87 #include <unistd.h>
88 #endif
89 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
90 #ifdef  AFS_AIX_ENV
91 #include <sys/statfs.h>
92 #include <sys/lockf.h>
93 #else
94 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
95 #include <sys/dk.h>
96 #endif
97 #endif
98 #endif
99 #include <afs/cellconfig.h>
100 #include <afs/keys.h>
101
102 #include <signal.h>
103 #include <afs/partition.h>
104 #include "viced_prototypes.h"
105 #include "viced.h"
106 #include "host.h"
107 #include "callback.h"
108 #include <afs/unified_afs.h>
109 #include <afs/audit.h>
110 #include <afs/afsutil.h>
111 #include <afs/dir.h>
112
113 extern void SetDirHandle(register DirHandle * dir, register Vnode * vnode);
114 extern void FidZap(DirHandle * file);
115 extern void FidZero(DirHandle * file);
116
117 #ifdef AFS_PTHREAD_ENV
118 pthread_mutex_t fileproc_glock_mutex;
119 #endif /* AFS_PTHREAD_ENV */
120
121 #ifdef O_LARGEFILE
122 #define afs_stat        stat64
123 #define afs_fstat       fstat64
124 #define afs_open        open64
125 #else /* !O_LARGEFILE */
126 #define afs_stat        stat
127 #define afs_fstat       fstat
128 #define afs_open        open
129 #endif /* !O_LARGEFILE */
130
131
132 /* Useful local defines used by this module */
133
134 #define DONTCHECK       0
135 #define MustNOTBeDIR    1
136 #define MustBeDIR       2
137
138 #define TVS_SDATA       1
139 #define TVS_SSTATUS     2
140 #define TVS_CFILE       4
141 #define TVS_SLINK       8
142 #define TVS_MKDIR       0x10
143
144 #define CHK_FETCH       0x10
145 #define CHK_FETCHDATA   0x10
146 #define CHK_FETCHACL    0x11
147 #define CHK_FETCHSTATUS 0x12
148 #define CHK_STOREDATA   0x00
149 #define CHK_STOREACL    0x01
150 #define CHK_STORESTATUS 0x02
151
152 #define OWNERREAD       0400
153 #define OWNERWRITE      0200
154 #define OWNEREXEC       0100
155 #ifdef USE_GROUP_PERMS
156 #define GROUPREAD       0040
157 #define GROUPWRITE      0020
158 #define GROUPREXEC      0010
159 #endif
160
161 /* The following errors were not defined in NT. They are given unique
162  * names here to avoid any potential collision.
163  */
164 #define FSERR_ELOOP              90
165 #define FSERR_EOPNOTSUPP        122
166 #define FSERR_ECONNREFUSED      130
167
168 #define NOTACTIVECALL   0
169 #define ACTIVECALL      1
170
171 #define CREATE_SGUID_ADMIN_ONLY 1
172
173 extern struct afsconf_dir *confDir;
174 extern afs_int32 dataVersionHigh;
175
176 extern int SystemId;
177 static struct AFSCallStatistics AFSCallStats;
178 #if FS_STATS_DETAILED
179 struct fs_stats_FullPerfStats afs_FullPerfStats;
180 extern int AnonymousID;
181 #endif /* FS_STATS_DETAILED */
182 #if OPENAFS_VOL_STATS
183 static const char nullString[] = "";
184 #endif /* OPENAFS_VOL_STATS */
185
186 struct afs_FSStats {
187     afs_int32 NothingYet;
188 };
189
190 struct afs_FSStats afs_fsstats;
191
192 void ResetDebug(), SetDebug(), Terminate();
193
194 int LogLevel = 0;
195 int supported = 1;
196 int Console = 0;
197 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
198 afs_int32 PctSpare;
199 extern afs_int32 implicitAdminRights;
200 extern afs_int32 readonlyServer;
201
202 /*
203  * Externals used by the xstat code.
204  */
205 extern VolPkgStats VStats;
206 extern int CEs, CEBlocks;
207
208 extern int HTs, HTBlocks;
209
210 afs_int32 FetchData_RXStyle(Volume * volptr, Vnode * targetptr,
211                             register struct rx_call *Call, afs_sfsize_t Pos,
212                             afs_sfsize_t Len, afs_int32 Int64Mode,
213 #if FS_STATS_DETAILED
214                             afs_sfsize_t * a_bytesToFetchP,
215                             afs_sfsize_t * a_bytesFetchedP
216 #endif                          /* FS_STATS_DETAILED */
217     );
218
219 afs_int32 StoreData_RXStyle(Volume * volptr, Vnode * targetptr,
220                             struct AFSFid *Fid, struct client *client,
221                             register struct rx_call *Call, afs_fsize_t Pos,
222                             afs_fsize_t Length, afs_fsize_t FileLength,
223                             int sync,
224 #if FS_STATS_DETAILED
225                             afs_sfsize_t * a_bytesToStoreP,
226                             afs_sfsize_t * a_bytesStoredP
227 #endif                          /* FS_STATS_DETAILED */
228     );
229
230 #ifdef AFS_SGI_XFS_IOPS_ENV
231 #include <afs/xfsattrs.h>
232 static int
233 GetLinkCount(Volume * avp, struct stat *astat)
234 {
235     if (!strcmp("xfs", astat->st_fstype)) {
236         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
237     } else
238         return astat->st_nlink;
239 }
240 #else
241 #define GetLinkCount(V, S) (S)->st_nlink
242 #endif
243
244 afs_int32
245 SpareComp(Volume * avolp)
246 {
247     register afs_int32 temp;
248
249     FS_LOCK;
250     if (PctSpare) {
251         temp = V_maxquota(avolp);
252         if (temp == 0) {
253             /* no matter; doesn't check in this case */
254             FS_UNLOCK;
255             return 0;
256         }
257         temp = (temp * PctSpare) / 100;
258         FS_UNLOCK;
259         return temp;
260     } else {
261         FS_UNLOCK;
262         return BlocksSpare;
263     }
264
265 }                               /*SpareComp */
266
267 /*
268  * Set the volume synchronization parameter for this volume.  If it changes,
269  * the Cache Manager knows that the volume must be purged from the stat cache.
270  */
271 static void
272 SetVolumeSync(register struct AFSVolSync *async, register Volume * avol)
273 {
274     FS_LOCK;
275     /* date volume instance was created */
276     if (async) {
277         if (avol)
278             async->spare1 = avol->header->diskstuff.creationDate;
279         else
280             async->spare1 = 0;
281         async->spare2 = 0;
282         async->spare3 = 0;
283         async->spare4 = 0;
284         async->spare5 = 0;
285         async->spare6 = 0;
286     }
287     FS_UNLOCK;
288 }                               /*SetVolumeSync */
289
290 /*
291  * Note that this function always returns a held host, so
292  * that CallPostamble can block without the host's disappearing.
293  * Call returns rx connection in passed in *tconn
294  */
295 static int
296 CallPreamble(register struct rx_call *acall, int activecall,
297              struct rx_connection **tconn, struct host **ahostp)
298 {
299     struct host *thost;
300     struct client *tclient;
301     int retry_flag = 1;
302     int code = 0;
303     char hoststr[16], hoststr2[16];
304     struct ubik_client *uclient;
305
306     *ahostp = NULL;
307
308     if (!tconn) {
309         ViceLog(0, ("CallPreamble: unexpected null tconn!\n"));
310         return -1;
311     }
312     *tconn = rx_ConnectionOf(acall);
313
314     H_LOCK;
315   retry:
316     tclient = h_FindClient_r(*tconn);
317     if (!tclient) {
318         ViceLog(0, ("CallPreamble: Couldn't get CPS. Too many lockers\n"));
319         H_UNLOCK;
320         return VBUSY;
321     }
322     thost = tclient->host;
323     if (tclient->prfail == 1) { /* couldn't get the CPS */
324         if (!retry_flag) {
325             h_ReleaseClient_r(tclient);
326             h_Release_r(thost);
327             ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
328             H_UNLOCK;
329             return -1001;
330         }
331         retry_flag = 0;         /* Retry once */
332
333         /* Take down the old connection and re-read the key file */
334         ViceLog(0,
335                 ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
336 #ifdef AFS_PTHREAD_ENV
337         uclient = (struct ubik_client *)pthread_getspecific(viced_uclient_key);
338
339         /* Is it still necessary to drop this? We hit the net, we should... */
340         H_UNLOCK;
341         if (uclient) 
342             hpr_End(uclient);
343         code = hpr_Initialize(&uclient);
344
345         if (!code)
346             assert(pthread_setspecific(viced_uclient_key, (void *)uclient) == 0);
347         H_LOCK;
348 #else
349         code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
350 #endif
351         if (code) {
352             h_ReleaseClient_r(tclient);
353             h_Release_r(thost);
354             H_UNLOCK;
355             ViceLog(0, ("CallPreamble: couldn't reconnect to ptserver\n"));
356             return -1001;
357         }
358
359         tclient->prfail = 2;    /* Means re-eval client's cps */
360         h_ReleaseClient_r(tclient);
361         h_Release_r(thost);
362         goto retry;
363     }
364
365     tclient->LastCall = thost->LastCall = FT_ApproxTime();
366     if (activecall)             /* For all but "GetTime", "GetStats", and "GetCaps" calls */
367         thost->ActiveCall = thost->LastCall;
368
369     h_Lock_r(thost);
370     if (thost->hostFlags & HOSTDELETED) {
371         ViceLog(3,
372                 ("Discarded a packet for deleted host %s:%d\n",
373                  afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port)));
374         code = VBUSY;           /* raced, so retry */
375     } else if ((thost->hostFlags & VENUSDOWN)
376                || (thost->hostFlags & HFE_LATER)) {
377         if (BreakDelayedCallBacks_r(thost)) {
378             ViceLog(0,
379                     ("BreakDelayedCallbacks FAILED for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
380                      afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2), 
381                      ntohs(rxr_PortOf(*tconn))));
382             if (MultiProbeAlternateAddress_r(thost)) {
383                 ViceLog(0,
384                         ("MultiProbe failed to find new address for host %s:%d\n",
385                          afs_inet_ntoa_r(thost->host, hoststr),
386                          ntohs(thost->port)));
387                 code = -1;
388             } else {
389                 ViceLog(0,
390                         ("MultiProbe found new address for host %s:%d\n",
391                          afs_inet_ntoa_r(thost->host, hoststr),
392                          ntohs(thost->port)));
393                 if (BreakDelayedCallBacks_r(thost)) {
394                     ViceLog(0,
395                             ("BreakDelayedCallbacks FAILED AGAIN for host %s:%d which IS UP.  Connection from %s:%d.  Possible network or routing failure.\n",
396                               afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port), afs_inet_ntoa_r(rxr_HostOf(*tconn), hoststr2), 
397                               ntohs(rxr_PortOf(*tconn))));
398                     code = -1;
399                 }
400             }
401         }
402     } else {
403         code = 0;
404     }
405
406     h_ReleaseClient_r(tclient);
407     h_Unlock_r(thost);
408     H_UNLOCK;
409     *ahostp = thost;
410     return code;
411
412 }                               /*CallPreamble */
413
414
415 static afs_int32
416 CallPostamble(register struct rx_connection *aconn, afs_int32 ret,
417               struct host *ahost)
418 {
419     struct host *thost;
420     struct client *tclient;
421     int translate = 0;
422     int held;
423
424     H_LOCK;
425     tclient = h_FindClient_r(aconn);
426     if (!tclient) 
427         goto busyout;
428     thost = tclient->host;
429     if (thost->hostFlags & HERRORTRANS)
430         translate = 1;
431     h_ReleaseClient_r(tclient);
432     held = h_Held_r(thost);
433     if (held)
434         h_Release_r(thost);
435     if (ahost && ahost != thost) {
436         char hoststr[16], hoststr2[16]; 
437         ViceLog(0, ("CallPostamble: ahost %s:%d (%x) != thost %s:%d (%x)\n",
438                 afs_inet_ntoa_r(ahost->host, hoststr), ntohs(ahost->port),
439                 ahost, 
440                 afs_inet_ntoa_r(thost->host, hoststr2), ntohs(thost->port),
441                 thost));
442         h_Release_r(ahost);
443     } else if (!ahost) {
444         char hoststr[16];       
445         ViceLog(0, ("CallPostamble: null ahost for thost %s:%d (%x)\n",
446                 afs_inet_ntoa_r(thost->host, hoststr), ntohs(thost->port),
447                 thost));
448     }
449  busyout:
450     H_UNLOCK;
451     return (translate ? sys_error_to_et(ret) : ret);
452 }                               /*CallPostamble */
453
454 /*
455  * Returns the volume and vnode pointers associated with file Fid; the lock
456  * type on the vnode is set to lock. Note that both volume/vnode's ref counts
457  * are incremented and they must be eventualy released.
458  */
459 static afs_int32
460 CheckVnode(AFSFid * fid, Volume ** volptr, Vnode ** vptr, int lock)
461 {
462     int fileCode = 0;
463     afs_int32 local_errorCode, errorCode = -1;
464     static struct timeval restartedat = { 0, 0 };
465
466     if (fid->Volume == 0 || fid->Vnode == 0)    /* not: || fid->Unique == 0) */
467         return (EINVAL);
468     if ((*volptr) == 0) {
469         extern int VInit;
470
471         while (1) {
472             int restarting = 
473 #ifdef AFS_DEMAND_ATTACH_FS
474                 VSALVAGE
475 #else
476                 VRESTARTING
477 #endif
478                 ;
479
480             errorCode = 0;
481             *volptr = VGetVolume(&local_errorCode, &errorCode, (afs_int32) fid->Volume);
482             if (!errorCode) {
483                 assert(*volptr);
484                 break;
485             }
486             if ((errorCode == VOFFLINE) && (VInit < 2)) {
487                 /* The volume we want may not be attached yet because
488                  * the volume initialization is not yet complete.
489                  * We can do several things: 
490                  *     1.  return -1, which will cause users to see
491                  *         "connection timed out".  This is more or
492                  *         less the same as always, except that the servers
493                  *         may appear to bounce up and down while they
494                  *         are actually restarting.
495                  *     2.  return VBUSY which will cause clients to 
496                  *         sleep and retry for 6.5 - 15 minutes, depending
497                  *         on what version of the CM they are running.  If
498                  *         the file server takes longer than that interval 
499                  *         to attach the desired volume, then the application
500                  *         will see an ENODEV or EIO.  This approach has 
501                  *         the advantage that volumes which have been attached
502                  *         are immediately available, it keeps the server's
503                  *         immediate backlog low, and the call is interruptible
504                  *         by the user.  Users see "waiting for busy volume."
505                  *     3.  sleep here and retry.  Some people like this approach
506                  *         because there is no danger of seeing errors.  However, 
507                  *         this approach only works with a bounded number of 
508                  *         clients, since the pending queues will grow without
509                  *         stopping.  It might be better to find a way to take
510                  *         this call and stick it back on a queue in order to
511                  *         recycle this thread for a different request.    
512                  *     4.  Return a new error code, which new cache managers will
513                  *         know enough to interpret as "sleep and retry", without
514                  *         the upper bound of 6-15 minutes that is imposed by the
515                  *         VBUSY handling.  Users will see "waiting for
516                  *         busy volume," so they know that something is
517                  *         happening.  Old cache managers must be able to do  
518                  *         something reasonable with this, for instance, mark the
519                  *         server down.  Fortunately, any error code < 0
520                  *         will elicit that behavior. See #1.
521                  *     5.  Some combination of the above.  I like doing #2 for 10
522                  *         minutes, followed by #4.  3.1b and 3.2 cache managers
523                  *         will be fine as long as the restart period is
524                  *         not longer than 6.5 minutes, otherwise they may
525                  *         return ENODEV to users.  3.3 cache managers will be
526                  *         fine for 10 minutes, then will return
527                  *         ETIMEDOUT.  3.4 cache managers will just wait
528                  *         until the call works or fails definitively.
529                  *  NB. The problem with 2,3,4,5 is that old clients won't
530                  *  fail over to an alternate read-only replica while this
531                  *  server is restarting.  3.4 clients will fail over right away.
532                  */
533                 if (restartedat.tv_sec == 0) {
534                     /* I'm not really worried about when we restarted, I'm   */
535                     /* just worried about when the first VBUSY was returned. */
536                     TM_GetTimeOfDay(&restartedat, 0);
537                     if (busyonrst) {
538                         FS_LOCK;
539                         afs_perfstats.fs_nBusies++;
540                         FS_UNLOCK;
541                     }
542                     return (busyonrst ? VBUSY : restarting);
543                 } else {
544                     struct timeval now;
545                     TM_GetTimeOfDay(&now, 0);
546                     if ((now.tv_sec - restartedat.tv_sec) < (11 * 60)) {
547                         if (busyonrst) {
548                             FS_LOCK;
549                             afs_perfstats.fs_nBusies++;
550                             FS_UNLOCK;
551                         }
552                         return (busyonrst ? VBUSY : restarting);
553                     } else {
554                         return (restarting);
555                     }
556                 }
557             }
558             /* allow read operations on busy volume. 
559              * must check local_errorCode because demand attach fs
560              * can have local_errorCode == VSALVAGING, errorCode == VBUSY */
561             else if (local_errorCode == VBUSY && lock == READ_LOCK) {
562                 errorCode = 0;
563                 break;
564             } else if (errorCode)
565                 return (errorCode);
566         }
567     }
568     assert(*volptr);
569
570     /* get the vnode  */
571     *vptr = VGetVnode(&errorCode, *volptr, fid->Vnode, lock);
572     if (errorCode)
573         return (errorCode);
574     if ((*vptr)->disk.uniquifier != fid->Unique) {
575         VPutVnode(&fileCode, *vptr);
576         assert(fileCode == 0);
577         *vptr = 0;
578         return (VNOVNODE);      /* return the right error code, at least */
579     }
580     return (0);
581 }                               /*CheckVnode */
582
583 /*
584  * This routine returns the ACL associated with the targetptr. If the
585  * targetptr isn't a directory, we access its parent dir and get the ACL
586  * thru the parent; in such case the parent's vnode is returned in
587  * READ_LOCK mode.
588  */
589 static afs_int32
590 SetAccessList(Vnode ** targetptr, Volume ** volume,
591               struct acl_accessList **ACL, int *ACLSize, Vnode ** parent,
592               AFSFid * Fid, int Lock)
593 {
594     if ((*targetptr)->disk.type == vDirectory) {
595         *parent = 0;
596         *ACL = VVnodeACL(*targetptr);
597         *ACLSize = VAclSize(*targetptr);
598         return (0);
599     } else {
600         assert(Fid != 0);
601         while (1) {
602             VnodeId parentvnode;
603             int errorCode = 0;
604
605             parentvnode = (*targetptr)->disk.parent;
606             VPutVnode(&errorCode, *targetptr);
607             *targetptr = 0;
608             if (errorCode)
609                 return (errorCode);
610             *parent = VGetVnode(&errorCode, *volume, parentvnode, READ_LOCK);
611             if (errorCode)
612                 return (errorCode);
613             *ACL = VVnodeACL(*parent);
614             *ACLSize = VAclSize(*parent);
615             if ((errorCode = CheckVnode(Fid, volume, targetptr, Lock)) != 0)
616                 return (errorCode);
617             if ((*targetptr)->disk.parent != parentvnode) {
618                 VPutVnode(&errorCode, *parent);
619                 *parent = 0;
620                 if (errorCode)
621                     return (errorCode);
622             } else
623                 return (0);
624         }
625     }
626
627 }                               /*SetAccessList */
628
629 /* Must not be called with H_LOCK held */
630 static void
631 client_CheckRights(struct client *client, struct acl_accessList *ACL, 
632                    afs_int32 *rights)
633 {
634     *rights = 0;
635     ObtainReadLock(&client->lock);
636     if (client->CPS.prlist_len > 0 && !client->deleted &&
637         client->host && !(client->host->hostFlags & HOSTDELETED))
638         acl_CheckRights(ACL, &client->CPS, rights);
639     ReleaseReadLock(&client->lock);
640 }
641
642 /* Must not be called with H_LOCK held */
643 static afs_int32
644 client_HasAsMember(struct client *client, afs_int32 id)
645 {
646     afs_int32 code = 0;
647
648     ObtainReadLock(&client->lock);
649     if (client->CPS.prlist_len > 0 && !client->deleted && 
650         client->host && !(client->host->hostFlags & HOSTDELETED))
651         code = acl_IsAMember(id, &client->CPS);
652     ReleaseReadLock(&client->lock);
653     return code;
654 }
655
656 /*
657  * Compare the directory's ACL with the user's access rights in the client
658  * connection and return the user's and everybody else's access permissions
659  * in rights and anyrights, respectively
660  */
661 static afs_int32
662 GetRights(struct client *client, struct acl_accessList *ACL,
663           afs_int32 * rights, afs_int32 * anyrights)
664 {
665     extern prlist SystemAnyUserCPS;
666     afs_int32 hrights = 0;
667 #ifndef AFS_PTHREAD_ENV
668     int code;
669 #endif
670
671     if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) {
672         ViceLog(0, ("CheckRights failed\n"));
673         *anyrights = 0;
674     }
675     *rights = 0;
676
677     client_CheckRights(client, ACL, rights);
678
679     /* wait if somebody else is already doing the getCPS call */
680     H_LOCK;
681     while (client->host->hostFlags & HCPS_INPROGRESS) {
682         client->host->hostFlags |= HCPS_WAITING;        /* I am waiting */
683 #ifdef AFS_PTHREAD_ENV
684         pthread_cond_wait(&client->host->cond, &host_glock_mutex);
685 #else /* AFS_PTHREAD_ENV */
686         if ((code =
687              LWP_WaitProcess(&(client->host->hostFlags))) != LWP_SUCCESS)
688             ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
689 #endif /* AFS_PTHREAD_ENV */
690     }
691
692     if (!client->host->hcps.prlist_len || !client->host->hcps.prlist_val) {
693         char hoststr[16];
694         ViceLog(5,
695                 ("CheckRights: len=%u, for host=%s:%d\n",
696                  client->host->hcps.prlist_len, 
697                  afs_inet_ntoa_r(client->host->host, hoststr),
698                  ntohs(client->host->port)));
699     } else
700         acl_CheckRights(ACL, &client->host->hcps, &hrights);
701     H_UNLOCK;
702     /* Allow system:admin the rights given with the -implicit option */
703     if (client_HasAsMember(client, SystemId))
704         *rights |= implicitAdminRights;
705
706     *rights |= hrights;
707     *anyrights |= hrights;
708
709     return (0);
710
711 }                               /*GetRights */
712
713 /*
714  * VanillaUser returns 1 (true) if the user is a vanilla user (i.e., not
715  * a System:Administrator)
716  */
717 static afs_int32
718 VanillaUser(struct client *client)
719 {
720     if (client_HasAsMember(client, SystemId))
721         return (0);             /* not a system administrator, then you're "vanilla" */
722     return (1);
723
724 }                               /*VanillaUser */
725
726
727 /*
728  * This unusual afs_int32-parameter routine encapsulates all volume package related
729  * operations together in a single function; it's called by almost all AFS
730  * interface calls.
731  */
732 static afs_int32
733 GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr,
734                  Vnode ** targetptr, int chkforDir, Vnode ** parent,
735                  struct client **client, int locktype, afs_int32 * rights,
736                  afs_int32 * anyrights)
737 {
738     struct acl_accessList *aCL; /* Internal access List */
739     int aCLSize;                /* size of the access list */
740     int errorCode = 0;          /* return code to caller */
741
742     if ((errorCode = CheckVnode(Fid, volptr, targetptr, locktype)))
743         return (errorCode);
744     if (chkforDir) {
745         if (chkforDir == MustNOTBeDIR
746             && ((*targetptr)->disk.type == vDirectory))
747             return (EISDIR);
748         else if (chkforDir == MustBeDIR
749                  && ((*targetptr)->disk.type != vDirectory))
750             return (ENOTDIR);
751     }
752     if ((errorCode =
753          SetAccessList(targetptr, volptr, &aCL, &aCLSize, parent,
754                        (chkforDir == MustBeDIR ? (AFSFid *) 0 : Fid),
755                        (chkforDir == MustBeDIR ? 0 : locktype))) != 0)
756         return (errorCode);
757     if (chkforDir == MustBeDIR)
758         assert((*parent) == 0);
759     if (!(*client)) {
760         if ((errorCode = GetClient(tcon, client)) != 0)
761             return (errorCode);
762         if (!(*client))
763             return (EINVAL);
764     }
765     GetRights(*client, aCL, rights, anyrights);
766     /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */
767     if ((*targetptr)->disk.type != vDirectory) {
768         /* anyuser can't be owner, so only have to worry about rights, not anyrights */
769         if ((*targetptr)->disk.owner == (*client)->ViceId)
770             (*rights) |= PRSFS_ADMINISTER;
771         else
772             (*rights) &= ~PRSFS_ADMINISTER;
773     }
774 #ifdef ADMIN_IMPLICIT_LOOKUP
775     /* admins get automatic lookup on everything */
776     if (!VanillaUser(*client))
777         (*rights) |= PRSFS_LOOKUP;
778 #endif /* ADMIN_IMPLICIT_LOOKUP */
779     return errorCode;
780
781 }                               /*GetVolumePackage */
782
783
784 /*
785  * This is the opposite of GetVolumePackage(), and is always used at the end of
786  * AFS calls to put back all used vnodes and the volume in the proper order!
787  */
788 static void
789 PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr,
790                  Vnode * parentptr, Volume * volptr, struct client **client)
791 {
792     int fileCode = 0;           /* Error code returned by the volume package */
793
794     if (parentwhentargetnotdir) {
795         VPutVnode(&fileCode, parentwhentargetnotdir);
796         assert(!fileCode || (fileCode == VSALVAGE));
797     }
798     if (targetptr) {
799         VPutVnode(&fileCode, targetptr);
800         assert(!fileCode || (fileCode == VSALVAGE));
801     }
802     if (parentptr) {
803         VPutVnode(&fileCode, parentptr);
804         assert(!fileCode || (fileCode == VSALVAGE));
805     }
806     if (volptr) {
807         VPutVolume(volptr);
808     }
809     if (*client) {
810         PutClient(client);
811     }
812 }                               /*PutVolumePackage */
813
814 static int
815 VolumeOwner(register struct client *client, register Vnode * targetptr)
816 {
817     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
818
819     if (owner >= 0)
820         return (client->ViceId == owner);
821     else {
822         /* 
823          * We don't have to check for host's cps since only regular
824          * viceid are volume owners.
825          */
826         return (client_HasAsMember(client, owner));
827     }
828
829 }                               /*VolumeOwner */
830
831 static int
832 VolumeRootVnode(Vnode * targetptr)
833 {
834     return ((targetptr->vnodeNumber == ROOTVNODE)
835             && (targetptr->disk.uniquifier == 1));
836
837 }                               /*VolumeRootVnode */
838
839 /*
840  * Check if target file has the proper access permissions for the Fetch
841  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
842  * StoreStatus) related calls
843  */
844 /* this code should probably just set a "priv" flag where all the audit events
845  * are now, and only generate the audit event once at the end of the routine, 
846  * thus only generating the event if all the checks succeed, but only because
847  * of the privilege       XXX
848  */
849 static afs_int32
850 Check_PermissionRights(Vnode * targetptr, struct client *client,
851                        afs_int32 rights, int CallingRoutine,
852                        AFSStoreStatus * InStatus)
853 {
854     int errorCode = 0;
855 #define OWNSp(client, target) ((client)->ViceId == (target)->disk.owner)
856 #define CHOWN(i,t) (((i)->Mask & AFS_SETOWNER) &&((i)->Owner != (t)->disk.owner))
857 #define CHGRP(i,t) (((i)->Mask & AFS_SETGROUP) &&((i)->Group != (t)->disk.group))
858
859     if (CallingRoutine & CHK_FETCH) {
860         if (CallingRoutine == CHK_FETCHDATA || VanillaUser(client)) {
861             if (targetptr->disk.type == vDirectory
862                 || targetptr->disk.type == vSymlink) {
863                 if (!(rights & PRSFS_LOOKUP)
864 #ifdef ADMIN_IMPLICIT_LOOKUP
865                     /* grant admins fetch on all directories */
866                     && VanillaUser(client)
867 #endif /* ADMIN_IMPLICIT_LOOKUP */
868                     && !VolumeOwner(client, targetptr))
869                     return (EACCES);
870             } else {            /* file */
871                 /* must have read access, or be owner and have insert access */
872                 if (!(rights & PRSFS_READ)
873                     && !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)))
874                     return (EACCES);
875             }
876             if (CallingRoutine == CHK_FETCHDATA
877                 && targetptr->disk.type == vFile)
878 #ifdef USE_GROUP_PERMS
879                 if (!OWNSp(client, targetptr)
880                     && !client_HasAsMember(client, targetptr->disk.owner)) {
881                     errorCode =
882                         (((GROUPREAD | GROUPEXEC) & targetptr->disk.modeBits)
883                          ? 0 : EACCES);
884                 } else {
885                     errorCode =
886                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.modeBits)
887                          ? 0 : EACCES);
888                 }
889 #else
890                 /*
891                  * The check with the ownership below is a kludge to allow
892                  * reading of files created with no read permission. The owner
893                  * of the file is always allowed to read it.
894                  */
895                 if ((client->ViceId != targetptr->disk.owner)
896                     && VanillaUser(client))
897                     errorCode =
898                         (((OWNERREAD | OWNEREXEC) & targetptr->disk.
899                           modeBits) ? 0 : EACCES);
900 #endif
901         } else {                /*  !VanillaUser(client) && !FetchData */
902
903             osi_audit(PrivilegeEvent, 0, AUD_ID,
904                       (client ? client->ViceId : 0), AUD_INT, CallingRoutine,
905                       AUD_END);
906         }
907     } else {                    /* a store operation */
908         if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
909             && (CallingRoutine != CHK_STOREACL)
910             && (targetptr->disk.type == vFile)) {
911             /* bypass protection checks on first store after a create
912              * for the creator; also prevent chowns during this time
913              * unless you are a system administrator */
914           /******  InStatus->Owner && UnixModeBits better be SET!! */
915             if (CHOWN(InStatus, targetptr) || CHGRP(InStatus, targetptr)) {
916                 if (readonlyServer)
917                     return (VREADONLY);
918                 else if (VanillaUser(client))
919                     return (EPERM);     /* Was EACCES */
920                 else
921                     osi_audit(PrivilegeEvent, 0, AUD_ID,
922                               (client ? client->ViceId : 0), AUD_INT,
923                               CallingRoutine, AUD_END);
924             }
925         } else {
926             if (CallingRoutine != CHK_STOREDATA && !VanillaUser(client)) {
927                 osi_audit(PrivilegeEvent, 0, AUD_ID,
928                           (client ? client->ViceId : 0), AUD_INT,
929                           CallingRoutine, AUD_END);
930             } else {
931                 if (readonlyServer) {
932                     return (VREADONLY);
933                 }
934                 if (CallingRoutine == CHK_STOREACL) {
935                     if (!(rights & PRSFS_ADMINISTER)
936                         && !VolumeOwner(client, targetptr))
937                         return (EACCES);
938                 } else {        /* store data or status */
939                     /* watch for chowns and chgrps */
940                     if (CHOWN(InStatus, targetptr)
941                         || CHGRP(InStatus, targetptr)) {
942                         if (readonlyServer)
943                             return (VREADONLY);
944                         else if (VanillaUser(client))
945                             return (EPERM);     /* Was EACCES */
946                         else
947                             osi_audit(PrivilegeEvent, 0, AUD_ID,
948                                       (client ? client->ViceId : 0), AUD_INT,
949                                       CallingRoutine, AUD_END);
950                     }
951                     /* must be sysadmin to set suid/sgid bits */
952                     if ((InStatus->Mask & AFS_SETMODE) &&
953 #ifdef AFS_NT40_ENV
954                         (InStatus->UnixModeBits & 0xc00) != 0) {
955 #else
956                         (InStatus->UnixModeBits & (S_ISUID | S_ISGID)) != 0) {
957 #endif
958                         if (readonlyServer)
959                             return (VREADONLY);
960                         if (VanillaUser(client))
961                             return (EACCES);
962                         else
963                             osi_audit(PrivSetID, 0, AUD_ID,
964                                       (client ? client->ViceId : 0), AUD_INT,
965                                       CallingRoutine, AUD_END);
966                     }
967                     if (CallingRoutine == CHK_STOREDATA) {
968                         if (readonlyServer)
969                             return (VREADONLY);
970                         if (!(rights & PRSFS_WRITE))
971                             return (EACCES);
972                         /* Next thing is tricky.  We want to prevent people
973                          * from writing files sans 0200 bit, but we want
974                          * creating new files with 0444 mode to work.  We
975                          * don't check the 0200 bit in the "you are the owner"
976                          * path above, but here we check the bit.  However, if
977                          * you're a system administrator, we ignore the 0200
978                          * bit anyway, since you may have fchowned the file,
979                          * too */
980 #ifdef USE_GROUP_PERMS
981                         if ((targetptr->disk.type == vFile)
982                             && VanillaUser(client)) {
983                             if (!OWNSp(client, targetptr)
984                                 && !client_HasAsMember(client, targetptr->disk.owner)) {
985                                 errorCode =
986                                     ((GROUPWRITE & targetptr->disk.modeBits)
987                                      ? 0 : EACCES);
988                             } else {
989                                 errorCode =
990                                     ((OWNERWRITE & targetptr->disk.modeBits)
991                                      ? 0 : EACCES);
992                             }
993                         } else
994 #endif
995                             if ((targetptr->disk.type != vDirectory)
996                                 && (!(targetptr->disk.modeBits & OWNERWRITE))) {
997                             if (readonlyServer)
998                                 return (VREADONLY);
999                             if (VanillaUser(client))
1000                                 return (EACCES);
1001                             else
1002                                 osi_audit(PrivilegeEvent, 0, AUD_ID,
1003                                           (client ? client->ViceId : 0),
1004                                           AUD_INT, CallingRoutine, AUD_END);
1005                         }
1006                     } else {    /* a status store */
1007                         if (readonlyServer)
1008                             return (VREADONLY);
1009                         if (targetptr->disk.type == vDirectory) {
1010                             if (!(rights & PRSFS_DELETE)
1011                                 && !(rights & PRSFS_INSERT))
1012                                 return (EACCES);
1013                         } else {        /* a file  or symlink */
1014                             if (!(rights & PRSFS_WRITE))
1015                                 return (EACCES);
1016                         }
1017                     }
1018                 }
1019             }
1020         }
1021     }
1022     return (errorCode);
1023
1024 }                               /*Check_PermissionRights */
1025
1026
1027 /*
1028  * The Access List information is converted from its internal form in the
1029  * target's vnode buffer (or its parent vnode buffer if not a dir), to an
1030  * external form and returned back to the caller, via the AccessList
1031  * structure
1032  */
1033 static afs_int32
1034 RXFetch_AccessList(Vnode * targetptr, Vnode * parentwhentargetnotdir,
1035                    struct AFSOpaque *AccessList)
1036 {
1037     char *eACL;                 /* External access list placeholder */
1038
1039     if (acl_Externalize
1040         ((targetptr->disk.type ==
1041           vDirectory ? VVnodeACL(targetptr) :
1042           VVnodeACL(parentwhentargetnotdir)), &eACL) != 0) {
1043         return EIO;
1044     }
1045     if ((strlen(eACL) + 1) > AFSOPAQUEMAX) {
1046         acl_FreeExternalACL(&eACL);
1047         return (E2BIG);
1048     } else {
1049         strcpy((char *)(AccessList->AFSOpaque_val), (char *)eACL);
1050         AccessList->AFSOpaque_len = strlen(eACL) + 1;
1051     }
1052     acl_FreeExternalACL(&eACL);
1053     return (0);
1054
1055 }                               /*RXFetch_AccessList */
1056
1057
1058 /*
1059  * The Access List information is converted from its external form in the
1060  * input AccessList structure to the internal representation and copied into
1061  * the target dir's vnode storage.
1062  */
1063 static afs_int32
1064 RXStore_AccessList(Vnode * targetptr, struct AFSOpaque *AccessList)
1065 {
1066     struct acl_accessList *newACL;      /* PlaceHolder for new access list */
1067
1068     if (acl_Internalize(AccessList->AFSOpaque_val, &newACL) != 0)
1069         return (EINVAL);
1070     if ((newACL->size + 4) > VAclSize(targetptr))
1071         return (E2BIG);
1072     memcpy((char *)VVnodeACL(targetptr), (char *)newACL, (int)(newACL->size));
1073     acl_FreeACL(&newACL);
1074     return (0);
1075
1076 }                               /*RXStore_AccessList */
1077
1078
1079 /* In our current implementation, each successive data store (new file
1080  * data version) creates a new inode. This function creates the new
1081  * inode, copies the old inode's contents to the new one, remove the old
1082  * inode (i.e. decrement inode count -- if it's currently used the delete
1083  * will be delayed), and modify some fields (i.e. vnode's
1084  * disk.inodeNumber and cloned)
1085  */
1086 #define COPYBUFFSIZE    8192
1087 static int
1088 CopyOnWrite(Vnode * targetptr, Volume * volptr)
1089 {
1090     Inode ino, nearInode;
1091     int rdlen;
1092     int wrlen;
1093     register afs_fsize_t size;
1094     register int length;
1095     char *buff;
1096     int rc;                     /* return code */
1097     IHandle_t *newH;            /* Use until finished copying, then cp to vnode. */
1098     FdHandle_t *targFdP;        /* Source Inode file handle */
1099     FdHandle_t *newFdP;         /* Dest Inode file handle */
1100
1101     if (targetptr->disk.type == vDirectory)
1102         DFlush();               /* just in case? */
1103
1104     VN_GET_LEN(size, targetptr);
1105     buff = (char *)malloc(COPYBUFFSIZE);
1106     if (buff == NULL) {
1107         return EIO;
1108     }
1109
1110     ino = VN_GET_INO(targetptr);
1111     if (!VALID_INO(ino)) {
1112         free(buff);
1113         VTakeOffline(volptr);
1114         ViceLog(0, ("Volume %u now offline, must be salvaged.\n",
1115                     volptr->hashid));
1116         return EIO;
1117     }    
1118     targFdP = IH_OPEN(targetptr->handle);
1119     if (targFdP == NULL) {
1120         rc = errno;
1121         ViceLog(0,
1122                 ("CopyOnWrite failed: Failed to open target vnode %u in volume %u (errno = %d)\n",
1123                  targetptr->vnodeNumber, V_id(volptr), rc));
1124         free(buff);
1125         VTakeOffline(volptr);
1126         return rc;
1127     }
1128
1129     nearInode = VN_GET_INO(targetptr);
1130     ino =
1131         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1132                   VPartitionPath(V_partition(volptr)), nearInode,
1133                   V_id(volptr), targetptr->vnodeNumber,
1134                   targetptr->disk.uniquifier,
1135                   (int)targetptr->disk.dataVersion);
1136     if (!VALID_INO(ino)) {
1137         ViceLog(0,
1138                 ("CopyOnWrite failed: Partition %s that contains volume %u may be out of free inodes(errno = %d)\n",
1139                  volptr->partition->name, V_id(volptr), errno));
1140         FDH_CLOSE(targFdP);
1141         free(buff);
1142         return ENOSPC;
1143     }
1144     IH_INIT(newH, V_device(volptr), V_id(volptr), ino);
1145     newFdP = IH_OPEN(newH);
1146     assert(newFdP != NULL);
1147
1148     while (size > 0) {
1149         if (size > COPYBUFFSIZE) {      /* more than a buffer */
1150             length = COPYBUFFSIZE;
1151             size -= COPYBUFFSIZE;
1152         } else {
1153             length = (int)size;
1154             size = 0;
1155         }
1156         rdlen = FDH_READ(targFdP, buff, length);
1157         if (rdlen == length)
1158             wrlen = FDH_WRITE(newFdP, buff, length);
1159         else
1160             wrlen = 0;
1161         /*  Callers of this function are not prepared to recover
1162          *  from error that put the filesystem in an inconsistent
1163          *  state. Make sure that we force the volume off-line if
1164          *  we some error other than ENOSPC - 4.29.99)
1165          *
1166          *  In case we are unable to write the required bytes, and the
1167          *  error code indicates that the disk is full, we roll-back to
1168          *  the initial state.
1169          */
1170         if ((rdlen != length) || (wrlen != length))
1171             if ((wrlen < 0) && (errno == ENOSPC)) {     /* disk full */
1172                 ViceLog(0,
1173                         ("CopyOnWrite failed: Partition %s containing volume %u is full\n",
1174                          volptr->partition->name, V_id(volptr)));
1175                 /* remove destination inode which was partially copied till now */
1176                 FDH_REALLYCLOSE(newFdP);
1177                 IH_RELEASE(newH);
1178                 FDH_REALLYCLOSE(targFdP);
1179                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1180                 if (!rc) {
1181                     ViceLog(0,
1182                             ("CopyOnWrite failed: error %u after i_dec on disk full, volume %u in partition %s needs salvage\n",
1183                              rc, V_id(volptr), volptr->partition->name));
1184                     VTakeOffline(volptr);
1185                 }
1186                 free(buff);
1187                 return ENOSPC;
1188             } else {
1189                 ViceLog(0,
1190                         ("CopyOnWrite failed: volume %u in partition %s  (tried reading %u, read %u, wrote %u, errno %u) volume needs salvage\n",
1191                          V_id(volptr), volptr->partition->name, length, rdlen,
1192                          wrlen, errno));
1193 #if defined(AFS_DEMAND_ATTACH_FS)
1194                 ViceLog(0, ("CopyOnWrite failed: requesting salvage\n"));
1195 #else
1196                 ViceLog(0, ("CopyOnWrite failed: taking volume offline\n"));
1197 #endif
1198                 /* Decrement this inode so salvager doesn't find it. */
1199                 FDH_REALLYCLOSE(newFdP);
1200                 IH_RELEASE(newH);
1201                 FDH_REALLYCLOSE(targFdP);
1202                 rc = IH_DEC(V_linkHandle(volptr), ino, V_parentId(volptr));
1203                 free(buff);
1204                 VTakeOffline(volptr);
1205                 return EIO;
1206             }
1207 #ifndef AFS_PTHREAD_ENV
1208         IOMGR_Poll();
1209 #endif /* !AFS_PTHREAD_ENV */
1210     }
1211     FDH_REALLYCLOSE(targFdP);
1212     rc = IH_DEC(V_linkHandle(volptr), VN_GET_INO(targetptr),
1213                 V_parentId(volptr));
1214     assert(!rc);
1215     IH_RELEASE(targetptr->handle);
1216
1217     rc = FDH_SYNC(newFdP);
1218     assert(rc == 0);
1219     FDH_CLOSE(newFdP);
1220     targetptr->handle = newH;
1221     VN_SET_INO(targetptr, ino);
1222     targetptr->disk.cloned = 0;
1223     /* Internal change to vnode, no user level change to volume - def 5445 */
1224     targetptr->changed_oldTime = 1;
1225     free(buff);
1226     return 0;                   /* success */
1227 }                               /*CopyOnWrite */
1228
1229
1230 /*
1231  * Common code to handle with removing the Name (file when it's called from
1232  * SAFS_RemoveFile() or an empty dir when called from SAFS_rmdir()) from a
1233  * given directory, parentptr.
1234  */
1235 int DT1 = 0, DT0 = 0;
1236 static afs_int32
1237 DeleteTarget(Vnode * parentptr, Volume * volptr, Vnode ** targetptr,
1238              DirHandle * dir, AFSFid * fileFid, char *Name, int ChkForDir)
1239 {
1240     DirHandle childdir;         /* Handle for dir package I/O */
1241     int errorCode = 0;
1242     int code;
1243
1244     /* watch for invalid names */
1245     if (!strcmp(Name, ".") || !strcmp(Name, ".."))
1246         return (EINVAL);
1247     if (parentptr->disk.cloned) {
1248         ViceLog(25, ("DeleteTarget : CopyOnWrite called\n"));
1249         if ((errorCode = CopyOnWrite(parentptr, volptr))) {
1250             ViceLog(20,
1251                     ("DeleteTarget %s: CopyOnWrite failed %d\n", Name,
1252                      errorCode));
1253             return errorCode;
1254         }
1255     }
1256
1257     /* check that the file is in the directory */
1258     SetDirHandle(dir, parentptr);
1259     if (Lookup(dir, Name, fileFid))
1260         return (ENOENT);
1261     fileFid->Volume = V_id(volptr);
1262
1263     /* just-in-case check for something causing deadlock */
1264     if (fileFid->Vnode == parentptr->vnodeNumber)
1265         return (EINVAL);
1266
1267     *targetptr = VGetVnode(&errorCode, volptr, fileFid->Vnode, WRITE_LOCK);
1268     if (errorCode) {
1269         return (errorCode);
1270     }
1271     if (ChkForDir == MustBeDIR) {
1272         if ((*targetptr)->disk.type != vDirectory)
1273             return (ENOTDIR);
1274     } else if ((*targetptr)->disk.type == vDirectory)
1275         return (EISDIR);
1276
1277     /*assert((*targetptr)->disk.uniquifier == fileFid->Unique); */
1278     /**
1279       * If the uniquifiers dont match then instead of asserting
1280       * take the volume offline and return VSALVAGE
1281       */
1282     if ((*targetptr)->disk.uniquifier != fileFid->Unique) {
1283         VTakeOffline(volptr);
1284         ViceLog(0,
1285                 ("Volume %u now offline, must be salvaged.\n",
1286                  volptr->hashid));
1287         errorCode = VSALVAGE;
1288         return errorCode;
1289     }
1290
1291     if (ChkForDir == MustBeDIR) {
1292         SetDirHandle(&childdir, *targetptr);
1293         if (IsEmpty(&childdir) != 0)
1294             return (EEXIST);
1295         DZap(&childdir);
1296         FidZap(&childdir);
1297         (*targetptr)->delete = 1;
1298     } else if ((--(*targetptr)->disk.linkCount) == 0)
1299         (*targetptr)->delete = 1;
1300     if ((*targetptr)->delete) {
1301         if (VN_GET_INO(*targetptr)) {
1302             DT0++;
1303             IH_REALLYCLOSE((*targetptr)->handle);
1304             errorCode =
1305                 IH_DEC(V_linkHandle(volptr), VN_GET_INO(*targetptr),
1306                        V_parentId(volptr));
1307             IH_RELEASE((*targetptr)->handle);
1308             if (errorCode == -1) {
1309                 ViceLog(0,
1310                         ("DT: inode=%s, name=%s, errno=%d\n",
1311                          PrintInode(NULL, VN_GET_INO(*targetptr)), Name,
1312                          errno));
1313                 if (errno != ENOENT)
1314                 {
1315                     VTakeOffline(volptr);
1316                     ViceLog(0,
1317                             ("Volume %u now offline, must be salvaged.\n",
1318                              volptr->hashid));
1319                     return (EIO);
1320                 }
1321                 DT1++;
1322                 errorCode = 0;
1323             }
1324         }
1325         VN_SET_INO(*targetptr, (Inode) 0);
1326         {
1327             afs_fsize_t adjLength;
1328             VN_GET_LEN(adjLength, *targetptr);
1329             VAdjustDiskUsage(&errorCode, volptr, -(int)nBlocks(adjLength), 0);
1330         }
1331     }
1332
1333     (*targetptr)->changed_newTime = 1;  /* Status change of deleted file/dir */
1334
1335     code = Delete(dir, (char *)Name);
1336     if (code) {
1337         ViceLog(0,
1338                 ("Error %d deleting %s\n", code,
1339                  (((*targetptr)->disk.type ==
1340                    Directory) ? "directory" : "file")));
1341         VTakeOffline(volptr);
1342         ViceLog(0,
1343                 ("Volume %u now offline, must be salvaged.\n",
1344                  volptr->hashid));
1345         if (!errorCode)
1346             errorCode = code;
1347     }
1348
1349     DFlush();
1350     return (errorCode);
1351
1352 }                               /*DeleteTarget */
1353
1354
1355 /*
1356  * This routine updates the parent directory's status block after the
1357  * specified operation (i.e. RemoveFile(), CreateFile(), Rename(),
1358  * SymLink(), Link(), MakeDir(), RemoveDir()) on one of its children has
1359  * been performed.
1360  */
1361 static void
1362 Update_ParentVnodeStatus(Vnode * parentptr, Volume * volptr, DirHandle * dir,
1363                          int author, int linkcount,
1364 #if FS_STATS_DETAILED
1365                          char a_inSameNetwork
1366 #endif                          /* FS_STATS_DETAILED */
1367     )
1368 {
1369     afs_fsize_t newlength;      /* Holds new directory length */
1370     afs_fsize_t parentLength;
1371     int errorCode;
1372 #if FS_STATS_DETAILED
1373     Date currDate;              /*Current date */
1374     int writeIdx;               /*Write index to bump */
1375     int timeIdx;                /*Authorship time index to bump */
1376 #endif /* FS_STATS_DETAILED */
1377
1378     parentptr->disk.dataVersion++;
1379     newlength = (afs_fsize_t) Length(dir);
1380     /* 
1381      * This is a called on both dir removals (i.e. remove, removedir, rename) but also in dir additions
1382      * (create, symlink, link, makedir) so we need to check if we have enough space
1383      * XXX But we still don't check the error since we're dealing with dirs here and really the increase
1384      * of a new entry would be too tiny to worry about failures (since we have all the existing cushion)
1385      */
1386     VN_GET_LEN(parentLength, parentptr);
1387     if (nBlocks(newlength) != nBlocks(parentLength)) {
1388         VAdjustDiskUsage(&errorCode, volptr,
1389                          (nBlocks(newlength) - nBlocks(parentLength)),
1390                          (nBlocks(newlength) - nBlocks(parentLength)));
1391     }
1392     VN_SET_LEN(parentptr, newlength);
1393
1394 #if FS_STATS_DETAILED
1395     /*
1396      * Update directory write stats for this volume.  Note that the auth
1397      * counter is located immediately after its associated ``distance''
1398      * counter.
1399      */
1400     if (a_inSameNetwork)
1401         writeIdx = VOL_STATS_SAME_NET;
1402     else
1403         writeIdx = VOL_STATS_DIFF_NET;
1404     V_stat_writes(volptr, writeIdx)++;
1405     if (author != AnonymousID) {
1406         V_stat_writes(volptr, writeIdx + 1)++;
1407     }
1408
1409     /*
1410      * Update the volume's authorship information in response to this
1411      * directory operation.  Get the current time, decide to which time
1412      * slot this operation belongs, and bump the appropriate slot.
1413      */
1414     currDate = (FT_ApproxTime() - parentptr->disk.unixModifyTime);
1415     timeIdx =
1416         (currDate < VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1417          VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1418          VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1419          VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1420          VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 : VOL_STATS_TIME_IDX_5);
1421     if (parentptr->disk.author == author) {
1422         V_stat_dirSameAuthor(volptr, timeIdx)++;
1423     } else {
1424         V_stat_dirDiffAuthor(volptr, timeIdx)++;
1425     }
1426 #endif /* FS_STATS_DETAILED */
1427
1428     parentptr->disk.author = author;
1429     parentptr->disk.linkCount = linkcount;
1430     parentptr->disk.unixModifyTime = FT_ApproxTime();   /* This should be set from CLIENT!! */
1431     parentptr->disk.serverModifyTime = FT_ApproxTime();
1432     parentptr->changed_newTime = 1;     /* vnode changed, write it back. */
1433 }
1434
1435
1436 /*
1437  * Update the target file's (or dir's) status block after the specified
1438  * operation is complete. Note that some other fields maybe updated by
1439  * the individual module.
1440  */
1441
1442 /* XXX INCOMPLETE - More attention is needed here! */
1443 static void
1444 Update_TargetVnodeStatus(Vnode * targetptr, afs_uint32 Caller,
1445                          struct client *client, AFSStoreStatus * InStatus,
1446                          Vnode * parentptr, Volume * volptr,
1447                          afs_fsize_t length)
1448 {
1449 #if FS_STATS_DETAILED
1450     Date currDate;              /*Current date */
1451     int writeIdx;               /*Write index to bump */
1452     int timeIdx;                /*Authorship time index to bump */
1453 #endif /* FS_STATS_DETAILED */
1454
1455     if (Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR)) { /* initialize new file */
1456         targetptr->disk.parent = parentptr->vnodeNumber;
1457         VN_SET_LEN(targetptr, length);
1458         /* targetptr->disk.group =      0;  save some cycles */
1459         targetptr->disk.modeBits = 0777;
1460         targetptr->disk.owner = client->ViceId;
1461         targetptr->disk.dataVersion = 0;        /* consistent with the client */
1462         targetptr->disk.linkCount = (Caller & TVS_MKDIR ? 2 : 1);
1463         /* the inode was created in Alloc_NewVnode() */
1464     }
1465 #if FS_STATS_DETAILED
1466     /*
1467      * Update file write stats for this volume.  Note that the auth
1468      * counter is located immediately after its associated ``distance''
1469      * counter.
1470      */
1471     if (client->InSameNetwork)
1472         writeIdx = VOL_STATS_SAME_NET;
1473     else
1474         writeIdx = VOL_STATS_DIFF_NET;
1475     V_stat_writes(volptr, writeIdx)++;
1476     if (client->ViceId != AnonymousID) {
1477         V_stat_writes(volptr, writeIdx + 1)++;
1478     }
1479
1480     /*
1481      * We only count operations that DON'T involve creating new objects
1482      * (files, symlinks, directories) or simply setting status as
1483      * authorship-change operations.
1484      */
1485     if (!(Caller & (TVS_CFILE | TVS_SLINK | TVS_MKDIR | TVS_SSTATUS))) {
1486         /*
1487          * Update the volume's authorship information in response to this
1488          * file operation.  Get the current time, decide to which time
1489          * slot this operation belongs, and bump the appropriate slot.
1490          */
1491         currDate = (FT_ApproxTime() - targetptr->disk.unixModifyTime);
1492         timeIdx =
1493             (currDate <
1494              VOL_STATS_TIME_CAP_0 ? VOL_STATS_TIME_IDX_0 : currDate <
1495              VOL_STATS_TIME_CAP_1 ? VOL_STATS_TIME_IDX_1 : currDate <
1496              VOL_STATS_TIME_CAP_2 ? VOL_STATS_TIME_IDX_2 : currDate <
1497              VOL_STATS_TIME_CAP_3 ? VOL_STATS_TIME_IDX_3 : currDate <
1498              VOL_STATS_TIME_CAP_4 ? VOL_STATS_TIME_IDX_4 :
1499              VOL_STATS_TIME_IDX_5);
1500         if (targetptr->disk.author == client->ViceId) {
1501             V_stat_fileSameAuthor(volptr, timeIdx)++;
1502         } else {
1503             V_stat_fileDiffAuthor(volptr, timeIdx)++;
1504         }
1505     }
1506 #endif /* FS_STATS_DETAILED */
1507
1508     if (!(Caller & TVS_SSTATUS))
1509         targetptr->disk.author = client->ViceId;
1510     if (Caller & TVS_SDATA) {
1511         targetptr->disk.dataVersion++;
1512         if (VanillaUser(client)) {
1513             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1514 #ifdef CREATE_SGUID_ADMIN_ONLY
1515             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1516 #endif
1517         }
1518     }
1519     if (Caller & TVS_SSTATUS) { /* update time on non-status change */
1520         /* store status, must explicitly request to change the date */
1521         if (InStatus->Mask & AFS_SETMODTIME)
1522             targetptr->disk.unixModifyTime = InStatus->ClientModTime;
1523     } else {                    /* other: date always changes, but perhaps to what is specified by caller */
1524         targetptr->disk.unixModifyTime =
1525             (InStatus->Mask & AFS_SETMODTIME ? InStatus->
1526              ClientModTime : FT_ApproxTime());
1527     }
1528     if (InStatus->Mask & AFS_SETOWNER) {
1529         /* admin is allowed to do chmod, chown as well as chown, chmod. */
1530         if (VanillaUser(client)) {
1531             targetptr->disk.modeBits &= ~04000; /* turn off suid for file. */
1532 #ifdef CREATE_SGUID_ADMIN_ONLY
1533             targetptr->disk.modeBits &= ~02000; /* turn off sgid for file. */
1534 #endif
1535         }
1536         targetptr->disk.owner = InStatus->Owner;
1537         if (VolumeRootVnode(targetptr)) {
1538             Error errorCode = 0;        /* what should be done with this? */
1539
1540             V_owner(targetptr->volumePtr) = InStatus->Owner;
1541             VUpdateVolume(&errorCode, targetptr->volumePtr);
1542         }
1543     }
1544     if (InStatus->Mask & AFS_SETMODE) {
1545         int modebits = InStatus->UnixModeBits;
1546 #define CREATE_SGUID_ADMIN_ONLY 1
1547 #ifdef CREATE_SGUID_ADMIN_ONLY
1548         if (VanillaUser(client))
1549             modebits = modebits & 0777;
1550 #endif
1551         if (VanillaUser(client)) {
1552             targetptr->disk.modeBits = modebits;
1553         } else {
1554             targetptr->disk.modeBits = modebits;
1555             switch (Caller) {
1556             case TVS_SDATA:
1557                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1558                           CHK_STOREDATA, AUD_END);
1559                 break;
1560             case TVS_CFILE:
1561             case TVS_SSTATUS:
1562                 osi_audit(PrivSetID, 0, AUD_ID, client->ViceId, AUD_INT,
1563                           CHK_STORESTATUS, AUD_END);
1564                 break;
1565             default:
1566                 break;
1567             }
1568         }
1569     }
1570     targetptr->disk.serverModifyTime = FT_ApproxTime();
1571     if (InStatus->Mask & AFS_SETGROUP)
1572         targetptr->disk.group = InStatus->Group;
1573     /* vnode changed : to be written back by VPutVnode */
1574     targetptr->changed_newTime = 1;
1575
1576 }                               /*Update_TargetVnodeStatus */
1577
1578
1579 /*
1580  * Fills the CallBack structure with the expiration time and type of callback
1581  * structure. Warning: this function is currently incomplete.
1582  */
1583 static void
1584 SetCallBackStruct(afs_uint32 CallBackTime, struct AFSCallBack *CallBack)
1585 {
1586     /* CallBackTime could not be 0 */
1587     if (CallBackTime == 0) {
1588         ViceLog(0, ("WARNING: CallBackTime == 0!\n"));
1589         CallBack->ExpirationTime = 0;
1590     } else
1591         CallBack->ExpirationTime = CallBackTime - FT_ApproxTime();
1592     CallBack->CallBackVersion = CALLBACK_VERSION;
1593     CallBack->CallBackType = CB_SHARED; /* The default for now */
1594
1595 }                               /*SetCallBackStruct */
1596
1597
1598 /*
1599  * Adjusts (Subtract) "length" number of blocks from the volume's disk
1600  * allocation; if some error occured (exceeded volume quota or partition
1601  * was full, or whatever), it frees the space back and returns the code.
1602  * We usually pre-adjust the volume space to make sure that there's
1603  * enough space before consuming some.
1604  */
1605 static afs_int32
1606 AdjustDiskUsage(Volume * volptr, afs_sfsize_t length,
1607                 afs_sfsize_t checkLength)
1608 {
1609     int rc;
1610     int nc;
1611
1612     VAdjustDiskUsage(&rc, volptr, length, checkLength);
1613     if (rc) {
1614         VAdjustDiskUsage(&nc, volptr, -length, 0);
1615         if (rc == VOVERQUOTA) {
1616             ViceLog(2,
1617                     ("Volume %u (%s) is full\n", V_id(volptr),
1618                      V_name(volptr)));
1619             return (rc);
1620         }
1621         if (rc == VDISKFULL) {
1622             ViceLog(0,
1623                     ("Partition %s that contains volume %u is full\n",
1624                      volptr->partition->name, V_id(volptr)));
1625             return (rc);
1626         }
1627         ViceLog(0, ("Got error return %d from VAdjustDiskUsage\n", rc));
1628         return (rc);
1629     }
1630     return (0);
1631
1632 }                               /*AdjustDiskUsage */
1633
1634 /*
1635  * Common code that handles the creation of a new file (SAFS_CreateFile and
1636  * SAFS_Symlink) or a new dir (SAFS_MakeDir)
1637  */
1638 static afs_int32
1639 Alloc_NewVnode(Vnode * parentptr, DirHandle * dir, Volume * volptr,
1640                Vnode ** targetptr, char *Name, struct AFSFid *OutFid,
1641                int FileType, afs_sfsize_t BlocksPreallocatedForVnode)
1642 {
1643     int errorCode = 0;          /* Error code returned back */
1644     int temp;
1645     Inode inode = 0;
1646     Inode nearInode;            /* hint for inode allocation in solaris */
1647
1648     if ((errorCode =
1649          AdjustDiskUsage(volptr, BlocksPreallocatedForVnode,
1650                          BlocksPreallocatedForVnode))) {
1651         ViceLog(25,
1652                 ("Insufficient space to allocate %lld blocks\n",
1653                  (afs_intmax_t) BlocksPreallocatedForVnode));
1654         return (errorCode);
1655     }
1656
1657     *targetptr = VAllocVnode(&errorCode, volptr, FileType);
1658     if (errorCode != 0) {
1659         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1660         return (errorCode);
1661     }
1662     OutFid->Volume = V_id(volptr);
1663     OutFid->Vnode = (*targetptr)->vnodeNumber;
1664     OutFid->Unique = (*targetptr)->disk.uniquifier;
1665
1666     nearInode = VN_GET_INO(parentptr);  /* parent is also in same vol */
1667
1668     /* create the inode now itself */
1669     inode =
1670         IH_CREATE(V_linkHandle(volptr), V_device(volptr),
1671                   VPartitionPath(V_partition(volptr)), nearInode,
1672                   V_id(volptr), (*targetptr)->vnodeNumber,
1673                   (*targetptr)->disk.uniquifier, 1);
1674
1675     /* error in creating inode */
1676     if (!VALID_INO(inode)) {
1677         ViceLog(0,
1678                 ("Volume : %u vnode = %u Failed to create inode: errno = %d\n",
1679                  (*targetptr)->volumePtr->header->diskstuff.id,
1680                  (*targetptr)->vnodeNumber, errno));
1681         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1682         (*targetptr)->delete = 1;       /* delete vnode */
1683         return ENOSPC;
1684     }
1685     VN_SET_INO(*targetptr, inode);
1686     IH_INIT(((*targetptr)->handle), V_device(volptr), V_id(volptr), inode);
1687
1688     /* copy group from parent dir */
1689     (*targetptr)->disk.group = parentptr->disk.group;
1690
1691     if (parentptr->disk.cloned) {
1692         ViceLog(25, ("Alloc_NewVnode : CopyOnWrite called\n"));
1693         if ((errorCode = CopyOnWrite(parentptr, volptr))) {     /* disk full */
1694             ViceLog(25, ("Alloc_NewVnode : CopyOnWrite failed\n"));
1695             /* delete the vnode previously allocated */
1696             (*targetptr)->delete = 1;
1697             VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1698             IH_REALLYCLOSE((*targetptr)->handle);
1699             if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1700                 ViceLog(0,
1701                         ("Alloc_NewVnode: partition %s idec %s failed\n",
1702                          volptr->partition->name, PrintInode(NULL, inode)));
1703             IH_RELEASE((*targetptr)->handle);
1704
1705             return errorCode;
1706         }
1707     }
1708
1709     /* add the name to the directory */
1710     SetDirHandle(dir, parentptr);
1711     if ((errorCode = Create(dir, (char *)Name, OutFid))) {
1712         (*targetptr)->delete = 1;
1713         VAdjustDiskUsage(&temp, volptr, -BlocksPreallocatedForVnode, 0);
1714         IH_REALLYCLOSE((*targetptr)->handle);
1715         if (IH_DEC(V_linkHandle(volptr), inode, V_parentId(volptr)))
1716             ViceLog(0,
1717                     ("Alloc_NewVnode: partition %s idec %s failed\n",
1718                      volptr->partition->name, PrintInode(NULL, inode)));
1719         IH_RELEASE((*targetptr)->handle);
1720         return (errorCode);
1721     }
1722     DFlush();
1723     return (0);
1724
1725 }                               /*Alloc_NewVnode */
1726
1727
1728 /*
1729  * Handle all the lock-related code (SAFS_SetLock, SAFS_ExtendLock and
1730  * SAFS_ReleaseLock)
1731  */
1732 static afs_int32
1733 HandleLocking(Vnode * targetptr, struct client *client, afs_int32 rights, ViceLockType LockingType)
1734 {
1735     int Time;                   /* Used for time */
1736     int writeVnode = targetptr->changed_oldTime;        /* save original status */
1737
1738     targetptr->changed_oldTime = 1;     /* locking doesn't affect any time stamp */
1739     Time = FT_ApproxTime();
1740     switch (LockingType) {
1741     case LockRead:
1742     case LockWrite:
1743         if (Time > targetptr->disk.lock.lockTime)
1744             targetptr->disk.lock.lockTime = targetptr->disk.lock.lockCount =
1745                 0;
1746         Time += AFS_LOCKWAIT;
1747         if (LockingType == LockRead) {
1748             if ( !(rights & PRSFS_LOCK) && 
1749                  !(rights & PRSFS_WRITE) &&
1750                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1751                     return(EACCES);
1752             return(EACCES);
1753
1754             if (targetptr->disk.lock.lockCount >= 0) {
1755                 ++(targetptr->disk.lock.lockCount);
1756                 targetptr->disk.lock.lockTime = Time;
1757             } else
1758                 return (EAGAIN);
1759         } else if (LockingType == LockWrite) {
1760             if ( !(rights & PRSFS_WRITE) && 
1761                  !(OWNSp(client, targetptr) && (rights & PRSFS_INSERT)) )
1762                 return(EACCES);
1763
1764             if (targetptr->disk.lock.lockCount == 0) {
1765                 targetptr->disk.lock.lockCount = -1;
1766                 targetptr->disk.lock.lockTime = Time;
1767             } else
1768                 return (EAGAIN);
1769         }
1770         break;
1771     case LockExtend:
1772         Time += AFS_LOCKWAIT;
1773         if (targetptr->disk.lock.lockCount != 0)
1774             targetptr->disk.lock.lockTime = Time;
1775         else
1776             return (EINVAL);
1777         break;
1778     case LockRelease:
1779         if ((--targetptr->disk.lock.lockCount) <= 0)
1780             targetptr->disk.lock.lockCount = targetptr->disk.lock.lockTime =
1781                 0;
1782         break;
1783     default:
1784         targetptr->changed_oldTime = writeVnode;        /* restore old status */
1785         ViceLog(0, ("Illegal Locking type %d\n", LockingType));
1786     }
1787     return (0);
1788 }                               /*HandleLocking */
1789
1790 /* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
1791
1792 static afs_int32
1793 CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
1794 {
1795     if (readonlyServer)
1796         return (VREADONLY);
1797     if (!(rights & Prfs_Mode))
1798         return (EACCES);
1799     if ((targetptr->disk.type != vDirectory)
1800         && (!(targetptr->disk.modeBits & OWNERWRITE)))
1801         return (EACCES);
1802     return (0);
1803 }
1804
1805 /*
1806  * If some flags (i.e. min or max quota) are set, the volume's in disk
1807  * label is updated; Name, OfflineMsg, and Motd are also reflected in the
1808  * update, if applicable.
1809  */
1810 static afs_int32
1811 RXUpdate_VolumeStatus(Volume * volptr, AFSStoreVolumeStatus * StoreVolStatus,
1812                       char *Name, char *OfflineMsg, char *Motd)
1813 {
1814     Error errorCode = 0;
1815
1816     if (StoreVolStatus->Mask & AFS_SETMINQUOTA)
1817         V_minquota(volptr) = StoreVolStatus->MinQuota;
1818     if (StoreVolStatus->Mask & AFS_SETMAXQUOTA)
1819         V_maxquota(volptr) = StoreVolStatus->MaxQuota;
1820     if (strlen(OfflineMsg) > 0) {
1821         strcpy(V_offlineMessage(volptr), OfflineMsg);
1822     }
1823     if (strlen(Name) > 0) {
1824         strcpy(V_name(volptr), Name);
1825     }
1826 #if OPENAFS_VOL_STATS
1827     /*
1828      * We don't overwrite the motd field, since it's now being used
1829      * for stats
1830      */
1831 #else
1832     if (strlen(Motd) > 0) {
1833         strcpy(V_motd(volptr), Motd);
1834     }
1835 #endif /* FS_STATS_DETAILED */
1836     VUpdateVolume(&errorCode, volptr);
1837     return (errorCode);
1838
1839 }                               /*RXUpdate_VolumeStatus */
1840
1841
1842 static afs_int32
1843 RXGetVolumeStatus(AFSFetchVolumeStatus * status, char **name, char **offMsg,
1844                   char **motd, Volume * volptr)
1845 {
1846     int temp;
1847
1848     status->Vid = V_id(volptr);
1849     status->ParentId = V_parentId(volptr);
1850     status->Online = V_inUse(volptr);
1851     status->InService = V_inService(volptr);
1852     status->Blessed = V_blessed(volptr);
1853     status->NeedsSalvage = V_needsSalvaged(volptr);
1854     if (VolumeWriteable(volptr))
1855         status->Type = ReadWrite;
1856     else
1857         status->Type = ReadOnly;
1858     status->MinQuota = V_minquota(volptr);
1859     status->MaxQuota = V_maxquota(volptr);
1860     status->BlocksInUse = V_diskused(volptr);
1861     status->PartBlocksAvail = RoundInt64ToInt32(volptr->partition->free);
1862     status->PartMaxBlocks = RoundInt64ToInt32(volptr->partition->totalUsable);
1863
1864     /* now allocate and copy these things; they're freed by the RXGEN stub */
1865     temp = strlen(V_name(volptr)) + 1;
1866     *name = malloc(temp);
1867     if (!*name) {
1868         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1869         assert(0);
1870     }
1871     strcpy(*name, V_name(volptr));
1872     temp = strlen(V_offlineMessage(volptr)) + 1;
1873     *offMsg = malloc(temp);
1874     if (!*offMsg) {
1875         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1876         assert(0);
1877     }
1878     strcpy(*offMsg, V_offlineMessage(volptr));
1879 #if OPENAFS_VOL_STATS
1880     *motd = malloc(1);
1881     if (!*motd) {
1882         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1883         assert(0);
1884     }
1885     strcpy(*motd, nullString);
1886 #else
1887     temp = strlen(V_motd(volptr)) + 1;
1888     *motd = malloc(temp);
1889     if (!*motd) {
1890         ViceLog(0, ("Failed malloc in RXGetVolumeStatus\n"));
1891         assert(0);
1892     }
1893     strcpy(*motd, V_motd(volptr));
1894 #endif /* FS_STATS_DETAILED */
1895     return 0;
1896 }                               /*RXGetVolumeStatus */
1897
1898
1899 static afs_int32
1900 FileNameOK(register char *aname)
1901 {
1902     register afs_int32 i, tc;
1903     i = strlen(aname);
1904     if (i >= 4) {
1905         /* watch for @sys on the right */
1906         if (strcmp(aname + i - 4, "@sys") == 0)
1907             return 0;
1908     }
1909     while ((tc = *aname++)) {
1910         if (tc == '/')
1911             return 0;           /* very bad character to encounter */
1912     }
1913     return 1;                   /* file name is ok */
1914
1915 }                               /*FileNameOK */
1916
1917
1918 /*
1919  * This variant of symlink is expressly to support the AFS/DFS translator
1920  * and is not supported by the AFS fileserver. We just return EINVAL.
1921  * The cache manager should not generate this call to an AFS cache manager.
1922  */
1923 afs_int32
1924 SRXAFS_DFSSymlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
1925                   char *LinkContents, struct AFSStoreStatus *InStatus,
1926                   struct AFSFid *OutFid, struct AFSFetchStatus *OutFidStatus,
1927                   struct AFSFetchStatus *OutDirStatus,
1928                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
1929 {
1930     return EINVAL;
1931 }
1932
1933 afs_int32
1934 SRXAFS_ResidencyCmd(struct rx_call * acall, struct AFSFid * Fid,
1935                     struct ResidencyCmdInputs * Inputs,
1936                     struct ResidencyCmdOutputs * Outputs)
1937 {
1938     return EINVAL;
1939 }
1940
1941 #ifdef AFS_NT40_ENV
1942 static struct afs_buffer {
1943     struct afs_buffer *next;
1944 } *freeBufferList = 0;
1945 static int afs_buffersAlloced = 0;
1946
1947 static
1948 FreeSendBuffer(register struct afs_buffer *adata)
1949 {
1950     FS_LOCK;
1951     afs_buffersAlloced--;
1952     adata->next = freeBufferList;
1953     freeBufferList = adata;
1954     FS_UNLOCK;
1955     return 0;
1956
1957 }                               /*FreeSendBuffer */
1958
1959 /* allocate space for sender */
1960 static char *
1961 AllocSendBuffer()
1962 {
1963     register struct afs_buffer *tp;
1964
1965     FS_LOCK;
1966     afs_buffersAlloced++;
1967     if (!freeBufferList) {
1968         char *tmp;
1969         FS_UNLOCK;
1970         tmp = malloc(sendBufSize);
1971         if (!tmp) {
1972             ViceLog(0, ("Failed malloc in AllocSendBuffer\n"));
1973             assert(0);
1974         }
1975         return tmp;
1976     }
1977     tp = freeBufferList;
1978     freeBufferList = tp->next;
1979     FS_UNLOCK;
1980     return (char *)tp;
1981
1982 }                               /*AllocSendBuffer */
1983 #endif /* AFS_NT40_ENV */
1984
1985 /*
1986  * This routine returns the status info associated with the targetptr vnode
1987  * in the AFSFetchStatus structure.  Some of the newer fields, such as
1988  * SegSize and Group are not yet implemented
1989  */
1990 static
1991     void
1992 GetStatus(Vnode * targetptr, AFSFetchStatus * status, afs_int32 rights,
1993           afs_int32 anyrights, Vnode * parentptr)
1994 {
1995     /* initialize return status from a vnode  */
1996     status->InterfaceVersion = 1;
1997     status->SyncCounter = status->dataVersionHigh = status->lockCount =
1998         status->errorCode = 0;
1999     status->ResidencyMask = 1;  /* means for MR-AFS: file in /vicepr-partition */
2000     if (targetptr->disk.type == vFile)
2001         status->FileType = File;
2002     else if (targetptr->disk.type == vDirectory)
2003         status->FileType = Directory;
2004     else if (targetptr->disk.type == vSymlink)
2005         status->FileType = SymbolicLink;
2006     else
2007         status->FileType = Invalid;     /*invalid type field */
2008     status->LinkCount = targetptr->disk.linkCount;
2009     {
2010         afs_fsize_t targetLen;
2011         VN_GET_LEN(targetLen, targetptr);
2012         SplitOffsetOrSize(targetLen, status->Length_hi, status->Length);
2013     }
2014     status->DataVersion = targetptr->disk.dataVersion;
2015     status->Author = targetptr->disk.author;
2016     status->Owner = targetptr->disk.owner;
2017     status->CallerAccess = rights;
2018     status->AnonymousAccess = anyrights;
2019     status->UnixModeBits = targetptr->disk.modeBits;
2020     status->ClientModTime = targetptr->disk.unixModifyTime;     /* This might need rework */
2021     status->ParentVnode =
2022         (status->FileType ==
2023          Directory ? targetptr->vnodeNumber : parentptr->vnodeNumber);
2024     status->ParentUnique =
2025         (status->FileType ==
2026          Directory ? targetptr->disk.uniquifier : parentptr->disk.uniquifier);
2027     status->ServerModTime = targetptr->disk.serverModifyTime;
2028     status->Group = targetptr->disk.group;
2029     status->lockCount = targetptr->disk.lock.lockCount;
2030     status->errorCode = 0;
2031
2032 }                               /*GetStatus */
2033
2034 static
2035   afs_int32
2036 common_FetchData64(struct rx_call *acall, struct AFSFid *Fid,
2037                    afs_sfsize_t Pos, afs_sfsize_t Len,
2038                    struct AFSFetchStatus *OutStatus,
2039                    struct AFSCallBack *CallBack, struct AFSVolSync *Sync,
2040                    int type)
2041 {
2042     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2043     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if vptr is a file */
2044     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2045     int errorCode = 0;          /* return code to caller */
2046     int fileCode = 0;           /* return code from vol package */
2047     Volume *volptr = 0;         /* pointer to the volume */
2048     struct client *client = 0;  /* pointer to the client data */
2049     struct rx_connection *tcon; /* the connection we're part of */
2050     struct host *thost;
2051     afs_int32 rights, anyrights;        /* rights for this and any user */
2052     struct client *t_client = NULL;     /* tmp ptr to client data */
2053     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2054 #if FS_STATS_DETAILED
2055     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2056     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2057     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2058     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2059     struct timeval elapsedTime; /* Transfer time */
2060     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2061     afs_sfsize_t bytesXferred;  /* # bytes actually xferred */
2062     int readIdx;                /* Index of read stats array to bump */
2063     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2064
2065     /*
2066      * Set our stats pointers, remember when the RPC operation started, and
2067      * tally the operation.
2068      */
2069     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
2070     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
2071     FS_LOCK;
2072     (opP->numOps)++;
2073     FS_UNLOCK;
2074     TM_GetTimeOfDay(&opStartTime, 0);
2075 #endif /* FS_STATS_DETAILED */
2076
2077     ViceLog(1,
2078             ("SRXAFS_FetchData, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2079              Fid->Unique));
2080     FS_LOCK;
2081     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
2082     FS_UNLOCK;
2083     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2084         goto Bad_FetchData;
2085
2086     /* Get ptr to client data for user Id for logging */
2087     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2088     logHostAddr.s_addr = rxr_HostOf(tcon);
2089     ViceLog(5,
2090             ("SRXAFS_FetchData, Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2091              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2092              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2093     /*
2094      * Get volume/vnode for the fetched file; caller's access rights to
2095      * it are also returned
2096      */
2097     if ((errorCode =
2098          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2099                           &parentwhentargetnotdir, &client, READ_LOCK,
2100                           &rights, &anyrights)))
2101         goto Bad_FetchData;
2102
2103     SetVolumeSync(Sync, volptr);
2104
2105 #if FS_STATS_DETAILED
2106     /*
2107      * Remember that another read operation was performed.
2108      */
2109     FS_LOCK;
2110     if (client->InSameNetwork)
2111         readIdx = VOL_STATS_SAME_NET;
2112     else
2113         readIdx = VOL_STATS_DIFF_NET;
2114     V_stat_reads(volptr, readIdx)++;
2115     if (client->ViceId != AnonymousID) {
2116         V_stat_reads(volptr, readIdx + 1)++;
2117     }
2118     FS_UNLOCK;
2119 #endif /* FS_STATS_DETAILED */
2120     /* Check whether the caller has permission access to fetch the data */
2121     if ((errorCode =
2122          Check_PermissionRights(targetptr, client, rights, CHK_FETCHDATA, 0)))
2123         goto Bad_FetchData;
2124
2125     /*
2126      * Drop the read lock on the parent directory after saving the parent
2127      * vnode information we need to pass to GetStatus
2128      */
2129     if (parentwhentargetnotdir != NULL) {
2130         tparentwhentargetnotdir = *parentwhentargetnotdir;
2131         VPutVnode(&fileCode, parentwhentargetnotdir);
2132         assert(!fileCode || (fileCode == VSALVAGE));
2133         parentwhentargetnotdir = NULL;
2134     }
2135 #if FS_STATS_DETAILED
2136     /*
2137      * Remember when the data transfer started.
2138      */
2139     TM_GetTimeOfDay(&xferStartTime, 0);
2140 #endif /* FS_STATS_DETAILED */
2141
2142     /* actually do the data transfer */
2143 #if FS_STATS_DETAILED
2144     errorCode =
2145         FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type,
2146                           &bytesToXfer, &bytesXferred);
2147 #else
2148     if ((errorCode =
2149          FetchData_RXStyle(volptr, targetptr, acall, Pos, Len, type)))
2150         goto Bad_FetchData;
2151 #endif /* FS_STATS_DETAILED */
2152
2153 #if FS_STATS_DETAILED
2154     /*
2155      * At this point, the data transfer is done, for good or ill.  Remember
2156      * when the transfer ended, bump the number of successes/failures, and
2157      * integrate the transfer size and elapsed time into the stats.  If the
2158      * operation failed, we jump to the appropriate point.
2159      */
2160     TM_GetTimeOfDay(&xferStopTime, 0);
2161     FS_LOCK;
2162     (xferP->numXfers)++;
2163     if (!errorCode) {
2164         (xferP->numSuccesses)++;
2165
2166         /*
2167          * Bump the xfer sum by the number of bytes actually sent, NOT the
2168          * target number.
2169          */
2170         tot_bytesXferred += bytesXferred;
2171         (xferP->sumBytes) += (tot_bytesXferred >> 10);
2172         tot_bytesXferred &= 0x3FF;
2173         if (bytesXferred < xferP->minBytes)
2174             xferP->minBytes = bytesXferred;
2175         if (bytesXferred > xferP->maxBytes)
2176             xferP->maxBytes = bytesXferred;
2177
2178         /*
2179          * Tally the size of the object.  Note: we tally the actual size,
2180          * NOT the number of bytes that made it out over the wire.
2181          */
2182         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
2183             (xferP->count[0])++;
2184         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
2185             (xferP->count[1])++;
2186         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
2187             (xferP->count[2])++;
2188         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
2189             (xferP->count[3])++;
2190         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
2191             (xferP->count[4])++;
2192         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
2193             (xferP->count[5])++;
2194         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
2195             (xferP->count[6])++;
2196         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
2197             (xferP->count[7])++;
2198         else
2199             (xferP->count[8])++;
2200
2201         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
2202         fs_stats_AddTo((xferP->sumTime), elapsedTime);
2203         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
2204         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
2205             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
2206         }
2207         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
2208             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
2209         }
2210     }
2211     FS_UNLOCK;
2212     /*
2213      * Finally, go off to tell our caller the bad news in case the
2214      * fetch failed.
2215      */
2216     if (errorCode)
2217         goto Bad_FetchData;
2218 #endif /* FS_STATS_DETAILED */
2219
2220     /* write back  the OutStatus from the target vnode  */
2221     GetStatus(targetptr, OutStatus, rights, anyrights,
2222               &tparentwhentargetnotdir);
2223
2224     /* if a r/w volume, promise a callback to the caller */
2225     if (VolumeWriteable(volptr))
2226         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2227     else {
2228         struct AFSFid myFid;
2229         memset(&myFid, 0, sizeof(struct AFSFid));
2230         myFid.Volume = Fid->Volume;
2231         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2232     }
2233
2234   Bad_FetchData:
2235     /* Update and store volume/vnode and parent vnodes back */
2236     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2237                            volptr, &client);
2238     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode));
2239     errorCode = CallPostamble(tcon, errorCode, thost);
2240
2241 #if FS_STATS_DETAILED
2242     TM_GetTimeOfDay(&opStopTime, 0);
2243     if (errorCode == 0) {
2244         FS_LOCK;
2245         (opP->numSuccesses)++;
2246         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2247         fs_stats_AddTo((opP->sumTime), elapsedTime);
2248         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2249         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2250             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2251         }
2252         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2253             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2254         }
2255         FS_UNLOCK;
2256     }
2257 #endif /* FS_STATS_DETAILED */
2258
2259     osi_auditU(acall, FetchDataEvent, errorCode, 
2260                AUD_ID, t_client ? t_client->ViceId : 0,
2261                AUD_FID, Fid, AUD_END);
2262     return (errorCode);
2263
2264 }                               /*SRXAFS_FetchData */
2265
2266 afs_int32
2267 SRXAFS_FetchData(struct rx_call * acall, struct AFSFid * Fid, afs_int32 Pos,
2268                  afs_int32 Len, struct AFSFetchStatus * OutStatus,
2269                  struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2270 {
2271     return common_FetchData64(acall, Fid, Pos, Len, OutStatus, CallBack, 
2272                               Sync, 0);
2273 }
2274
2275 afs_int32
2276 SRXAFS_FetchData64(struct rx_call * acall, struct AFSFid * Fid, afs_int64 Pos,
2277                    afs_int64 Len, struct AFSFetchStatus * OutStatus,
2278                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2279 {
2280     int code;
2281     afs_sfsize_t tPos, tLen;
2282
2283 #ifdef AFS_64BIT_ENV
2284 #ifndef AFS_LARGEFILE_ENV
2285     if (Pos + Len > 0x7fffffff)
2286         return EFBIG;
2287 #endif /* !AFS_LARGEFILE_ENV */
2288     tPos = (afs_sfsize_t) Pos;
2289     tLen = (afs_sfsize_t) Len;
2290 #else /* AFS_64BIT_ENV */
2291     if (Pos.high || Len.high)
2292         return EFBIG;
2293     tPos = Pos.low;
2294     tLen = Len.low;
2295 #endif /* AFS_64BIT_ENV */
2296
2297     code =
2298         common_FetchData64(acall, Fid, tPos, tLen, OutStatus, CallBack, Sync,
2299                            1);
2300     return code;
2301 }
2302
2303 afs_int32
2304 SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid,
2305                 struct AFSOpaque * AccessList,
2306                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
2307 {
2308     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2309     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2310     int errorCode = 0;          /* return error code to caller */
2311     Volume *volptr = 0;         /* pointer to the volume */
2312     struct client *client = 0;  /* pointer to the client data */
2313     afs_int32 rights, anyrights;        /* rights for this and any user */
2314     struct rx_connection *tcon = rx_ConnectionOf(acall);
2315     struct host *thost;
2316     struct client *t_client = NULL;     /* tmp ptr to client data */
2317     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2318 #if FS_STATS_DETAILED
2319     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2320     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2321     struct timeval elapsedTime; /* Transfer time */
2322
2323     /*
2324      * Set our stats pointer, remember when the RPC operation started, and
2325      * tally the operation.
2326      */
2327     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
2328     FS_LOCK;
2329     (opP->numOps)++;
2330     FS_UNLOCK;
2331     TM_GetTimeOfDay(&opStartTime, 0);
2332 #endif /* FS_STATS_DETAILED */
2333
2334     ViceLog(1,
2335             ("SAFS_FetchACL, Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2336              Fid->Unique));
2337     FS_LOCK;
2338     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
2339     FS_UNLOCK;
2340     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2341         goto Bad_FetchACL;
2342
2343     /* Get ptr to client data for user Id for logging */
2344     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2345     logHostAddr.s_addr = rxr_HostOf(tcon);
2346     ViceLog(5,
2347             ("SAFS_FetchACL, Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2348              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2349              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2350
2351     AccessList->AFSOpaque_len = 0;
2352     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
2353     if (!AccessList->AFSOpaque_val) {
2354         ViceLog(0, ("Failed malloc in SRXAFS_FetchACL\n"));
2355         assert(0);
2356     }
2357
2358     /*
2359      * Get volume/vnode for the fetched file; caller's access rights to it
2360      * are also returned
2361      */
2362     if ((errorCode =
2363          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2364                           &parentwhentargetnotdir, &client, READ_LOCK,
2365                           &rights, &anyrights)))
2366         goto Bad_FetchACL;
2367
2368     SetVolumeSync(Sync, volptr);
2369
2370     /* Check whether we have permission to fetch the ACL */
2371     if ((errorCode =
2372          Check_PermissionRights(targetptr, client, rights, CHK_FETCHACL, 0)))
2373         goto Bad_FetchACL;
2374
2375     /* Get the Access List from the dir's vnode */
2376     if ((errorCode =
2377          RXFetch_AccessList(targetptr, parentwhentargetnotdir, AccessList)))
2378         goto Bad_FetchACL;
2379
2380     /* Get OutStatus back From the target Vnode  */
2381     GetStatus(targetptr, OutStatus, rights, anyrights,
2382               parentwhentargetnotdir);
2383
2384   Bad_FetchACL:
2385     /* Update and store volume/vnode and parent vnodes back */
2386     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2387                            volptr, &client);
2388     ViceLog(2,
2389             ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode,
2390              AccessList->AFSOpaque_val));
2391     errorCode = CallPostamble(tcon, errorCode, thost);
2392
2393 #if FS_STATS_DETAILED
2394     TM_GetTimeOfDay(&opStopTime, 0);
2395     if (errorCode == 0) {
2396         FS_LOCK;
2397         (opP->numSuccesses)++;
2398         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2399         fs_stats_AddTo((opP->sumTime), elapsedTime);
2400         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2401         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2402             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2403         }
2404         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2405             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2406         }
2407         FS_UNLOCK;
2408     }
2409 #endif /* FS_STATS_DETAILED */
2410
2411     osi_auditU(acall, FetchACLEvent, errorCode, 
2412                AUD_ID, t_client ? t_client->ViceId : 0,
2413                AUD_FID, Fid, 
2414                AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
2415     return errorCode;
2416 }                               /*SRXAFS_FetchACL */
2417
2418
2419 /*
2420  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
2421  * merged into it when possible.
2422  */
2423 static
2424   afs_int32
2425 SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid,
2426                   struct AFSFetchStatus *OutStatus,
2427                   struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
2428 {
2429     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2430     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2431     int errorCode = 0;          /* return code to caller */
2432     Volume *volptr = 0;         /* pointer to the volume */
2433     struct client *client = 0;  /* pointer to the client data */
2434     afs_int32 rights, anyrights;        /* rights for this and any user */
2435     struct client *t_client = NULL;     /* tmp ptr to client data */
2436     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2437     struct rx_connection *tcon = rx_ConnectionOf(acall);
2438
2439     /* Get ptr to client data for user Id for logging */
2440     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2441     logHostAddr.s_addr = rxr_HostOf(tcon);
2442     ViceLog(1,
2443             ("SAFS_FetchStatus,  Fid = %u.%u.%u, Host %s:%d, Id %d\n",
2444              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2445              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2446     FS_LOCK;
2447     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
2448     FS_UNLOCK;
2449     /*
2450      * Get volume/vnode for the fetched file; caller's rights to it are
2451      * also returned
2452      */
2453     if ((errorCode =
2454          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
2455                           &parentwhentargetnotdir, &client, READ_LOCK,
2456                           &rights, &anyrights)))
2457         goto Bad_FetchStatus;
2458
2459     /* set volume synchronization information */
2460     SetVolumeSync(Sync, volptr);
2461
2462     /* Are we allowed to fetch Fid's status? */
2463     if (targetptr->disk.type != vDirectory) {
2464         if ((errorCode =
2465              Check_PermissionRights(targetptr, client, rights,
2466                                     CHK_FETCHSTATUS, 0))) {
2467             if (rx_GetCallAbortCode(acall) == errorCode)
2468                 rx_SetCallAbortCode(acall, 0);
2469             goto Bad_FetchStatus;
2470         }
2471     }
2472
2473     /* set OutStatus From the Fid  */
2474     GetStatus(targetptr, OutStatus, rights, anyrights,
2475               parentwhentargetnotdir);
2476
2477     /* If a r/w volume, also set the CallBack state */
2478     if (VolumeWriteable(volptr))
2479         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
2480     else {
2481         struct AFSFid myFid;
2482         memset(&myFid, 0, sizeof(struct AFSFid));
2483         myFid.Volume = Fid->Volume;
2484         SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
2485     }
2486
2487   Bad_FetchStatus:
2488     /* Update and store volume/vnode and parent vnodes back */
2489     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2490                            volptr, &client);
2491     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode));
2492     return errorCode;
2493
2494 }                               /*SAFSS_FetchStatus */
2495
2496
2497 afs_int32
2498 SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2499                   struct AFSBulkStats * OutStats, struct AFSCBs * CallBacks,
2500                   struct AFSVolSync * Sync)
2501 {
2502     register int i;
2503     afs_int32 nfiles;
2504     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2505     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2506     int errorCode = 0;          /* return code to caller */
2507     Volume *volptr = 0;         /* pointer to the volume */
2508     struct client *client = 0;  /* pointer to the client data */
2509     afs_int32 rights, anyrights;        /* rights for this and any user */
2510     register struct AFSFid *tfid;       /* file id we're dealing with now */
2511     struct rx_connection *tcon = rx_ConnectionOf(acall);
2512     struct host *thost;
2513     struct client *t_client = NULL;     /* tmp pointer to the client data */
2514 #if FS_STATS_DETAILED
2515     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2516     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2517     struct timeval elapsedTime; /* Transfer time */
2518
2519     /*
2520      * Set our stats pointer, remember when the RPC operation started, and
2521      * tally the operation.
2522      */
2523     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2524     FS_LOCK;
2525     (opP->numOps)++;
2526     FS_UNLOCK;
2527     TM_GetTimeOfDay(&opStartTime, 0);
2528 #endif /* FS_STATS_DETAILED */
2529
2530     ViceLog(1, ("SAFS_BulkStatus\n"));
2531     FS_LOCK;
2532     AFSCallStats.TotalCalls++;
2533     FS_UNLOCK;
2534     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2535     if (nfiles <= 0) {          /* Sanity check */
2536         errorCode = EINVAL;
2537         goto Audit_and_Return;
2538     }
2539
2540     /* allocate space for return output parameters */
2541     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2542         malloc(nfiles * sizeof(struct AFSFetchStatus));
2543     if (!OutStats->AFSBulkStats_val) {
2544         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2545         assert(0);
2546     }
2547     OutStats->AFSBulkStats_len = nfiles;
2548     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2549         malloc(nfiles * sizeof(struct AFSCallBack));
2550     if (!CallBacks->AFSCBs_val) {
2551         ViceLog(0, ("Failed malloc in SRXAFS_BulkStatus\n"));
2552         assert(0);
2553     }
2554     CallBacks->AFSCBs_len = nfiles;
2555
2556     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2557         goto Bad_BulkStatus;
2558
2559     tfid = Fids->AFSCBFids_val;
2560     for (i = 0; i < nfiles; i++, tfid++) {
2561         /*
2562          * Get volume/vnode for the fetched file; caller's rights to it
2563          * are also returned
2564          */
2565         if ((errorCode =
2566              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2567                               &parentwhentargetnotdir, &client, READ_LOCK,
2568                               &rights, &anyrights)))
2569             goto Bad_BulkStatus;
2570         /* set volume synchronization information, but only once per call */
2571         if (i == nfiles)
2572             SetVolumeSync(Sync, volptr);
2573
2574         /* Are we allowed to fetch Fid's status? */
2575         if (targetptr->disk.type != vDirectory) {
2576             if ((errorCode =
2577                  Check_PermissionRights(targetptr, client, rights,
2578                                         CHK_FETCHSTATUS, 0))) {
2579                 if (rx_GetCallAbortCode(acall) == errorCode)
2580                     rx_SetCallAbortCode(acall, 0);
2581                 goto Bad_BulkStatus;
2582             }
2583         }
2584
2585         /* set OutStatus From the Fid  */
2586         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i], rights,
2587                   anyrights, parentwhentargetnotdir);
2588
2589         /* If a r/w volume, also set the CallBack state */
2590         if (VolumeWriteable(volptr))
2591             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2592                               &CallBacks->AFSCBs_val[i]);
2593         else {
2594             struct AFSFid myFid;
2595             memset(&myFid, 0, sizeof(struct AFSFid));
2596             myFid.Volume = tfid->Volume;
2597             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2598                               &CallBacks->AFSCBs_val[i]);
2599         }
2600
2601         /* put back the file ID and volume */
2602         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2603                                volptr, &client);
2604         parentwhentargetnotdir = (Vnode *) 0;
2605         targetptr = (Vnode *) 0;
2606         volptr = (Volume *) 0;
2607         client = (struct client *)0;
2608     }
2609
2610   Bad_BulkStatus:
2611     /* Update and store volume/vnode and parent vnodes back */
2612     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2613                            volptr, &client);
2614     errorCode = CallPostamble(tcon, errorCode, thost);
2615
2616     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2617
2618 #if FS_STATS_DETAILED
2619     TM_GetTimeOfDay(&opStopTime, 0);
2620     if (errorCode == 0) {
2621         FS_LOCK;
2622         (opP->numSuccesses)++;
2623         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2624         fs_stats_AddTo((opP->sumTime), elapsedTime);
2625         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2626         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2627             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2628         }
2629         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2630             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2631         }
2632         FS_UNLOCK;
2633     }
2634 #endif /* FS_STATS_DETAILED */
2635
2636   Audit_and_Return:
2637     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode));
2638     osi_auditU(acall, BulkFetchStatusEvent, errorCode, 
2639                AUD_ID, t_client ? t_client->ViceId : 0,
2640                AUD_FIDS, Fids, AUD_END);
2641     return errorCode;
2642
2643 }                               /*SRXAFS_BulkStatus */
2644
2645
2646 afs_int32
2647 SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids,
2648                         struct AFSBulkStats * OutStats,
2649                         struct AFSCBs * CallBacks, struct AFSVolSync * Sync)
2650 {
2651     register int i;
2652     afs_int32 nfiles;
2653     Vnode *targetptr = 0;       /* pointer to vnode to fetch */
2654     Vnode *parentwhentargetnotdir = 0;  /* parent vnode if targetptr is a file */
2655     int errorCode = 0;          /* return code to caller */
2656     Volume *volptr = 0;         /* pointer to the volume */
2657     struct client *client = 0;  /* pointer to the client data */
2658     afs_int32 rights, anyrights;        /* rights for this and any user */
2659     register struct AFSFid *tfid;       /* file id we're dealing with now */
2660     struct rx_connection *tcon;
2661     struct host *thost;
2662     struct client *t_client = NULL;     /* tmp ptr to client data */
2663     AFSFetchStatus *tstatus;
2664 #if FS_STATS_DETAILED
2665     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2666     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2667     struct timeval elapsedTime; /* Transfer time */
2668
2669     /*
2670      * Set our stats pointer, remember when the RPC operation started, and
2671      * tally the operation.
2672      */
2673     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
2674     FS_LOCK;
2675     (opP->numOps)++;
2676     FS_UNLOCK;
2677     TM_GetTimeOfDay(&opStartTime, 0);
2678 #endif /* FS_STATS_DETAILED */
2679
2680     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
2681     FS_LOCK;
2682     AFSCallStats.TotalCalls++;
2683     FS_UNLOCK;
2684     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
2685     if (nfiles <= 0) {          /* Sanity check */
2686         errorCode = EINVAL;
2687         goto Audit_and_Return;
2688     }
2689
2690     /* allocate space for return output parameters */
2691     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
2692         malloc(nfiles * sizeof(struct AFSFetchStatus));
2693     if (!OutStats->AFSBulkStats_val) {
2694         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2695         assert(0);
2696     }
2697     OutStats->AFSBulkStats_len = nfiles;
2698     CallBacks->AFSCBs_val = (struct AFSCallBack *)
2699         malloc(nfiles * sizeof(struct AFSCallBack));
2700     if (!CallBacks->AFSCBs_val) {
2701         ViceLog(0, ("Failed malloc in SRXAFS_FetchStatus\n"));
2702         assert(0);
2703     }
2704     CallBacks->AFSCBs_len = nfiles;
2705
2706     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost))) {
2707         goto Bad_InlineBulkStatus;
2708     }
2709
2710     tfid = Fids->AFSCBFids_val;
2711     for (i = 0; i < nfiles; i++, tfid++) {
2712         /*
2713          * Get volume/vnode for the fetched file; caller's rights to it
2714          * are also returned
2715          */
2716         if ((errorCode =
2717              GetVolumePackage(tcon, tfid, &volptr, &targetptr, DONTCHECK,
2718                               &parentwhentargetnotdir, &client, READ_LOCK,
2719                               &rights, &anyrights))) {
2720             tstatus = &OutStats->AFSBulkStats_val[i];
2721             tstatus->errorCode = errorCode;
2722             PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
2723                              volptr, &client);
2724             parentwhentargetnotdir = (Vnode *) 0;
2725             targetptr = (Vnode *) 0;
2726             volptr = (Volume *) 0;
2727             client = (struct client *)0;
2728             continue;
2729         }
2730
2731         /* set volume synchronization information, but only once per call */
2732         if (i == nfiles)
2733             SetVolumeSync(Sync, volptr);
2734
2735         /* Are we allowed to fetch Fid's status? */
2736         if (targetptr->disk.type != vDirectory) {
2737             if ((errorCode =
2738                  Check_PermissionRights(targetptr, client, rights,
2739                                         CHK_FETCHSTATUS, 0))) {
2740                 tstatus = &OutStats->AFSBulkStats_val[i];
2741                 tstatus->errorCode = errorCode;
2742                 (void)PutVolumePackage(parentwhentargetnotdir, targetptr,
2743                                        (Vnode *) 0, volptr, &client);
2744                 parentwhentargetnotdir = (Vnode *) 0;
2745                 targetptr = (Vnode *) 0;
2746                 volptr = (Volume *) 0;
2747                 client = (struct client *)0;
2748                 continue;
2749             }
2750         }
2751
2752         /* set OutStatus From the Fid  */
2753         GetStatus(targetptr,
2754                   (struct AFSFetchStatus *)&OutStats->AFSBulkStats_val[i],
2755                   rights, anyrights, parentwhentargetnotdir);
2756
2757         /* If a r/w volume, also set the CallBack state */
2758         if (VolumeWriteable(volptr))
2759             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
2760                               &CallBacks->AFSCBs_val[i]);
2761         else {
2762             struct AFSFid myFid;
2763             memset(&myFid, 0, sizeof(struct AFSFid));
2764             myFid.Volume = tfid->Volume;
2765             SetCallBackStruct(AddVolCallBack(client->host, &myFid),
2766                               &CallBacks->AFSCBs_val[i]);
2767         }
2768
2769         /* put back the file ID and volume */
2770         (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2771                                volptr, &client);
2772         parentwhentargetnotdir = (Vnode *) 0;
2773         targetptr = (Vnode *) 0;
2774         volptr = (Volume *) 0;
2775         client = (struct client *)0;
2776     }
2777
2778   Bad_InlineBulkStatus:
2779     /* Update and store volume/vnode and parent vnodes back */
2780     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
2781                            volptr, &client);
2782     errorCode = CallPostamble(tcon, errorCode, thost);
2783
2784     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2785
2786 #if FS_STATS_DETAILED
2787     TM_GetTimeOfDay(&opStopTime, 0);
2788     if (errorCode == 0) {
2789         FS_LOCK;
2790         (opP->numSuccesses)++;
2791         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2792         fs_stats_AddTo((opP->sumTime), elapsedTime);
2793         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2794         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2795             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2796         }
2797         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2798             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2799         }
2800         FS_UNLOCK;
2801     }
2802 #endif /* FS_STATS_DETAILED */
2803
2804   Audit_and_Return:
2805     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode));
2806     osi_auditU(acall, InlineBulkFetchStatusEvent, errorCode, 
2807                AUD_ID, t_client ? t_client->ViceId : 0,
2808                AUD_FIDS, Fids, AUD_END);
2809     return 0;
2810
2811 }                               /*SRXAFS_InlineBulkStatus */
2812
2813
2814 afs_int32
2815 SRXAFS_FetchStatus(struct rx_call * acall, struct AFSFid * Fid,
2816                    struct AFSFetchStatus * OutStatus,
2817                    struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
2818 {
2819     afs_int32 code;
2820     struct rx_connection *tcon;
2821     struct host *thost;
2822     struct client *t_client = NULL;     /* tmp ptr to client data */
2823 #if FS_STATS_DETAILED
2824     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2825     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2826     struct timeval elapsedTime; /* Transfer time */
2827
2828     /*
2829      * Set our stats pointer, remember when the RPC operation started, and
2830      * tally the operation.
2831      */
2832     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
2833     FS_LOCK;
2834     (opP->numOps)++;
2835     FS_UNLOCK;
2836     TM_GetTimeOfDay(&opStartTime, 0);
2837 #endif /* FS_STATS_DETAILED */
2838
2839     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2840         goto Bad_FetchStatus;
2841
2842     code = SAFSS_FetchStatus(acall, Fid, OutStatus, CallBack, Sync);
2843
2844   Bad_FetchStatus:
2845     code = CallPostamble(tcon, code, thost);
2846
2847     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2848
2849 #if FS_STATS_DETAILED
2850     TM_GetTimeOfDay(&opStopTime, 0);
2851     if (code == 0) {
2852         FS_LOCK;
2853         (opP->numSuccesses)++;
2854         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2855         fs_stats_AddTo((opP->sumTime), elapsedTime);
2856         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2857         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2858             fs_stats_TimeAssign((opP->minTime), elapsedTime);
2859         }
2860         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2861             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2862         }
2863         FS_UNLOCK;
2864     }
2865 #endif /* FS_STATS_DETAILED */
2866
2867     osi_auditU(acall, FetchStatusEvent, code, 
2868                AUD_ID, t_client ? t_client->ViceId : 0,
2869                AUD_FID, Fid, AUD_END);
2870     return code;
2871
2872 }                               /*SRXAFS_FetchStatus */
2873
2874 static
2875   afs_int32
2876 common_StoreData64(struct rx_call *acall, struct AFSFid *Fid,
2877                    struct AFSStoreStatus *InStatus, afs_fsize_t Pos,
2878                    afs_fsize_t Length, afs_fsize_t FileLength,
2879                    struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
2880 {
2881     Vnode *targetptr = 0;       /* pointer to input fid */
2882     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
2883     Vnode tparentwhentargetnotdir;      /* parent vnode for GetStatus */
2884     int errorCode = 0;          /* return code for caller */
2885     int fileCode = 0;           /* return code from vol package */
2886     Volume *volptr = 0;         /* pointer to the volume header */
2887     struct client *client = 0;  /* pointer to client structure */
2888     afs_int32 rights, anyrights;        /* rights for this and any user */
2889     struct client *t_client = NULL;     /* tmp ptr to client data */
2890     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
2891     struct rx_connection *tcon;
2892     struct host *thost;
2893 #if FS_STATS_DETAILED
2894     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
2895     struct fs_stats_xferData *xferP;    /* Ptr to this op's byte size struct */
2896     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
2897     struct timeval xferStartTime, xferStopTime; /* Start/stop times for xfer portion */
2898     struct timeval elapsedTime; /* Transfer time */
2899     afs_sfsize_t bytesToXfer;   /* # bytes to xfer */
2900     afs_sfsize_t bytesXferred;  /* # bytes actually xfer */
2901     static afs_int32 tot_bytesXferred;  /* shared access protected by FS_LOCK */
2902
2903     /*
2904      * Set our stats pointers, remember when the RPC operation started, and
2905      * tally the operation.
2906      */
2907     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
2908     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
2909     FS_LOCK;
2910     (opP->numOps)++;
2911     FS_UNLOCK;
2912     ViceLog(1,
2913             ("StoreData: Fid = %u.%u.%u\n", Fid->Volume, Fid->Vnode,
2914              Fid->Unique));
2915     TM_GetTimeOfDay(&opStartTime, 0);
2916 #endif /* FS_STATS_DETAILED */
2917
2918     FS_LOCK;
2919     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
2920     FS_UNLOCK;
2921     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
2922         goto Bad_StoreData;
2923
2924     /* Get ptr to client data for user Id for logging */
2925     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2926     logHostAddr.s_addr = rxr_HostOf(tcon);
2927     ViceLog(5,
2928             ("StoreData: Fid = %u.%u.%u, Host %s:%d, Id %d\n", Fid->Volume,
2929              Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
2930              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
2931
2932     /*
2933      * Get associated volume/vnode for the stored file; caller's rights
2934      * are also returned
2935      */
2936     if ((errorCode =
2937          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustNOTBeDIR,
2938                           &parentwhentargetnotdir, &client, WRITE_LOCK,
2939                           &rights, &anyrights))) {
2940         goto Bad_StoreData;
2941     }
2942
2943     /* set volume synchronization information */
2944     SetVolumeSync(Sync, volptr);
2945
2946     if ((targetptr->disk.type == vSymlink)) {
2947         /* Should we return a better error code here??? */
2948         errorCode = EISDIR;
2949         goto Bad_StoreData;
2950     }
2951
2952     /* Check if we're allowed to store the data */
2953     if ((errorCode =
2954          Check_PermissionRights(targetptr, client, rights, CHK_STOREDATA,
2955                                 InStatus))) {
2956         goto Bad_StoreData;
2957     }
2958
2959     /*
2960      * Drop the read lock on the parent directory after saving the parent
2961      * vnode information we need to pass to GetStatus
2962      */
2963     if (parentwhentargetnotdir != NULL) {
2964         tparentwhentargetnotdir = *parentwhentargetnotdir;
2965         VPutVnode(&fileCode, parentwhentargetnotdir);
2966         assert(!fileCode || (fileCode == VSALVAGE));
2967         parentwhentargetnotdir = NULL;
2968     }
2969 #if FS_STATS_DETAILED
2970     /*
2971      * Remember when the data transfer started.
2972      */
2973     TM_GetTimeOfDay(&xferStartTime, 0);
2974 #endif /* FS_STATS_DETAILED */
2975
2976     /* Do the actual storing of the data */
2977 #if FS_STATS_DETAILED
2978     errorCode =
2979         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2980                           FileLength, (InStatus->Mask & AFS_FSYNC),
2981                           &bytesToXfer, &bytesXferred);
2982 #else
2983     errorCode =
2984         StoreData_RXStyle(volptr, targetptr, Fid, client, acall, Pos, Length,
2985                           FileLength, (InStatus->Mask & AFS_FSYNC));
2986     if (errorCode && (!targetptr->changed_newTime))
2987         goto Bad_StoreData;
2988 #endif /* FS_STATS_DETAILED */
2989 #if FS_STATS_DETAILED
2990     /*
2991      * At this point, the data transfer is done, for good or ill.  Remember
2992      * when the transfer ended, bump the number of successes/failures, and
2993      * integrate the transfer size and elapsed time into the stats.  If the
2994      * operation failed, we jump to the appropriate point.
2995      */
2996     TM_GetTimeOfDay(&xferStopTime, 0);
2997     FS_LOCK;
2998     (xferP->numXfers)++;
2999     if (!errorCode) {
3000         (xferP->numSuccesses)++;
3001
3002         /*
3003          * Bump the xfer sum by the number of bytes actually sent, NOT the
3004          * target number.
3005          */
3006         tot_bytesXferred += bytesXferred;
3007         (xferP->sumBytes) += (tot_bytesXferred >> 10);
3008         tot_bytesXferred &= 0x3FF;
3009         if (bytesXferred < xferP->minBytes)
3010             xferP->minBytes = bytesXferred;
3011         if (bytesXferred > xferP->maxBytes)
3012             xferP->maxBytes = bytesXferred;
3013
3014         /*
3015          * Tally the size of the object.  Note: we tally the actual size,
3016          * NOT the number of bytes that made it out over the wire.
3017          */
3018         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
3019             (xferP->count[0])++;
3020         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
3021             (xferP->count[1])++;
3022         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
3023             (xferP->count[2])++;
3024         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
3025             (xferP->count[3])++;
3026         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
3027             (xferP->count[4])++;
3028         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
3029             (xferP->count[5])++;
3030         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
3031             (xferP->count[6])++;
3032         else if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
3033             (xferP->count[7])++;
3034         else
3035             (xferP->count[8])++;
3036
3037         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
3038         fs_stats_AddTo((xferP->sumTime), elapsedTime);
3039         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
3040         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
3041             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
3042         }
3043         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
3044             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
3045         }
3046     }
3047     FS_UNLOCK;
3048     /*
3049      * Finally, go off to tell our caller the bad news in case the
3050      * store failed.
3051      */
3052     if (errorCode && (!targetptr->changed_newTime))
3053         goto Bad_StoreData;
3054 #endif /* FS_STATS_DETAILED */
3055
3056     /* Update the status of the target's vnode */
3057     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus,
3058                              targetptr, volptr, 0);
3059
3060     /* Get the updated File's status back to the caller */
3061     GetStatus(targetptr, OutStatus, rights, anyrights,
3062               &tparentwhentargetnotdir);
3063
3064   Bad_StoreData:
3065     /* Update and store volume/vnode and parent vnodes back */
3066     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0,
3067                            volptr, &client);
3068     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
3069
3070     errorCode = CallPostamble(tcon, errorCode, thost);
3071
3072 #if FS_STATS_DETAILED
3073     TM_GetTimeOfDay(&opStopTime, 0);
3074     if (errorCode == 0) {
3075         FS_LOCK;
3076         (opP->numSuccesses)++;
3077         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3078         fs_stats_AddTo((opP->sumTime), elapsedTime);
3079         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3080         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3081             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3082         }
3083         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3084             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3085         }
3086         FS_UNLOCK;
3087     }
3088 #endif /* FS_STATS_DETAILED */
3089     osi_auditU(acall, StoreDataEvent, errorCode, 
3090                AUD_ID, t_client ? t_client->ViceId : 0,
3091                AUD_FID, Fid, AUD_END);
3092     return (errorCode);
3093 }                               /*common_StoreData64 */
3094
3095 afs_int32
3096 SRXAFS_StoreData(struct rx_call * acall, struct AFSFid * Fid,
3097                  struct AFSStoreStatus * InStatus, afs_uint32 Pos,
3098                  afs_uint32 Length, afs_uint32 FileLength,
3099                  struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3100 {
3101     if (FileLength > 0x7fffffff || Pos > 0x7fffffff || 
3102         (0x7fffffff - Pos) < Length)
3103         return EFBIG;
3104
3105     return common_StoreData64(acall, Fid, InStatus, Pos, Length, FileLength,
3106                               OutStatus, Sync);
3107 }                               /*SRXAFS_StoreData */
3108
3109 afs_int32
3110 SRXAFS_StoreData64(struct rx_call * acall, struct AFSFid * Fid,
3111                    struct AFSStoreStatus * InStatus, afs_uint64 Pos,
3112                    afs_uint64 Length, afs_uint64 FileLength,
3113                    struct AFSFetchStatus * OutStatus,
3114                    struct AFSVolSync * Sync)
3115 {
3116     int code;
3117     afs_fsize_t tPos;
3118     afs_fsize_t tLength;
3119     afs_fsize_t tFileLength;
3120
3121 #ifdef AFS_64BIT_ENV
3122 #ifndef AFS_LARGEFILE_ENV
3123     if (FileLength > 0x7fffffff)
3124         return EFBIG;
3125 #endif /* !AFS_LARGEFILE_ENV */
3126     tPos = (afs_fsize_t) Pos;
3127     tLength = (afs_fsize_t) Length;
3128     tFileLength = (afs_fsize_t) FileLength;
3129 #else /* AFS_64BIT_ENV */
3130     if (FileLength.high)
3131         return EFBIG;
3132     tPos = Pos.low;
3133     tLength = Length.low;
3134     tFileLength = FileLength.low;
3135 #endif /* AFS_64BIT_ENV */
3136
3137     code =
3138         common_StoreData64(acall, Fid, InStatus, tPos, tLength, tFileLength,
3139                            OutStatus, Sync);
3140     return code;
3141 }
3142
3143 afs_int32
3144 SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid,
3145                 struct AFSOpaque * AccessList,
3146                 struct AFSFetchStatus * OutStatus, struct AFSVolSync * Sync)
3147 {
3148     Vnode *targetptr = 0;       /* pointer to input fid */
3149     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3150     int errorCode = 0;          /* return code for caller */
3151     struct AFSStoreStatus InStatus;     /* Input status for fid */
3152     Volume *volptr = 0;         /* pointer to the volume header */
3153     struct client *client = 0;  /* pointer to client structure */
3154     afs_int32 rights, anyrights;        /* rights for this and any user */
3155     struct rx_connection *tcon;
3156     struct host *thost;
3157     struct client *t_client = NULL;     /* tmp ptr to client data */
3158     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3159 #if FS_STATS_DETAILED
3160     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3161     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3162     struct timeval elapsedTime; /* Transfer time */
3163
3164     /*
3165      * Set our stats pointer, remember when the RPC operation started, and
3166      * tally the operation.
3167      */
3168     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
3169     FS_LOCK;
3170     (opP->numOps)++;
3171     FS_UNLOCK;
3172     TM_GetTimeOfDay(&opStartTime, 0);
3173 #endif /* FS_STATS_DETAILED */
3174     if ((errorCode = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3175         goto Bad_StoreACL;
3176
3177     /* Get ptr to client data for user Id for logging */
3178     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3179     logHostAddr.s_addr = rxr_HostOf(tcon);
3180     ViceLog(1,
3181             ("SAFS_StoreACL, Fid = %u.%u.%u, ACL=%s, Host %s:%d, Id %d\n",
3182              Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
3183              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3184     FS_LOCK;
3185     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
3186     FS_UNLOCK;
3187     InStatus.Mask = 0;          /* not storing any status */
3188
3189     /*
3190      * Get associated volume/vnode for the target dir; caller's rights
3191      * are also returned.
3192      */
3193     if ((errorCode =
3194          GetVolumePackage(tcon, Fid, &volptr, &targetptr, MustBeDIR,
3195                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3196                           &rights, &anyrights))) {
3197         goto Bad_StoreACL;
3198     }
3199
3200     /* set volume synchronization information */
3201     SetVolumeSync(Sync, volptr);
3202
3203     /* Check if we have permission to change the dir's ACL */
3204     if ((errorCode =
3205          Check_PermissionRights(targetptr, client, rights, CHK_STOREACL,
3206                                 &InStatus))) {
3207         goto Bad_StoreACL;
3208     }
3209
3210     /* Build and store the new Access List for the dir */
3211     if ((errorCode = RXStore_AccessList(targetptr, AccessList))) {
3212         goto Bad_StoreACL;
3213     }
3214
3215     targetptr->changed_newTime = 1;     /* status change of directory */
3216
3217     /* convert the write lock to a read lock before breaking callbacks */
3218     VVnodeWriteToRead(&errorCode, targetptr);
3219     assert(!errorCode || errorCode == VSALVAGE);
3220
3221     /* break call backs on the directory  */
3222     BreakCallBack(client->host, Fid, 0);
3223
3224     /* Get the updated dir's status back to the caller */
3225     GetStatus(targetptr, OutStatus, rights, anyrights, 0);
3226
3227   Bad_StoreACL:
3228     /* Update and store volume/vnode and parent vnodes back */
3229     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3230                      volptr, &client);
3231     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode));
3232     errorCode = CallPostamble(tcon, errorCode, thost);
3233
3234 #if FS_STATS_DETAILED
3235     TM_GetTimeOfDay(&opStopTime, 0);
3236     if (errorCode == 0) {
3237         FS_LOCK;
3238         (opP->numSuccesses)++;
3239         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3240         fs_stats_AddTo((opP->sumTime), elapsedTime);
3241         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3242         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3243             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3244         }
3245         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3246             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3247         }
3248         FS_UNLOCK;
3249     }
3250 #endif /* FS_STATS_DETAILED */
3251
3252     osi_auditU(acall, StoreACLEvent, errorCode, 
3253                AUD_ID, t_client ? t_client->ViceId : 0,
3254                AUD_FID, Fid, AUD_ACL, AccessList->AFSOpaque_val, AUD_END);
3255     return errorCode;
3256
3257 }                               /*SRXAFS_StoreACL */
3258
3259
3260 /*
3261  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
3262  * should be merged when possible.
3263  */
3264 static afs_int32
3265 SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid,
3266                   struct AFSStoreStatus *InStatus,
3267                   struct AFSFetchStatus *OutStatus, struct AFSVolSync *Sync)
3268 {
3269     Vnode *targetptr = 0;       /* pointer to input fid */
3270     Vnode *parentwhentargetnotdir = 0;  /* parent of Fid to get ACL */
3271     int errorCode = 0;          /* return code for caller */
3272     Volume *volptr = 0;         /* pointer to the volume header */
3273     struct client *client = 0;  /* pointer to client structure */
3274     afs_int32 rights, anyrights;        /* rights for this and any user */
3275     struct client *t_client = NULL;     /* tmp ptr to client data */
3276     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3277     struct rx_connection *tcon = rx_ConnectionOf(acall);
3278
3279     /* Get ptr to client data for user Id for logging */
3280     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3281     logHostAddr.s_addr = rxr_HostOf(tcon);
3282     ViceLog(1,
3283             ("SAFS_StoreStatus,  Fid    = %u.%u.%u, Host %s:%d, Id %d\n",
3284              Fid->Volume, Fid->Vnode, Fid->Unique, inet_ntoa(logHostAddr),
3285              ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3286     FS_LOCK;
3287     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
3288     FS_UNLOCK;
3289     /*
3290      * Get volume/vnode for the target file; caller's rights to it are
3291      * also returned
3292      */
3293     if ((errorCode =
3294          GetVolumePackage(tcon, Fid, &volptr, &targetptr, DONTCHECK,
3295                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3296                           &rights, &anyrights))) {
3297         goto Bad_StoreStatus;
3298     }
3299
3300     /* set volume synchronization information */
3301     SetVolumeSync(Sync, volptr);
3302
3303     /* Check if the caller has proper permissions to store status to Fid */
3304     if ((errorCode =
3305          Check_PermissionRights(targetptr, client, rights, CHK_STORESTATUS,
3306                                 InStatus))) {
3307         goto Bad_StoreStatus;
3308     }
3309     /*
3310      * Check for a symbolic link; we can't chmod these (otherwise could
3311      * change a symlink to a mt pt or vice versa)
3312      */
3313     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
3314         errorCode = EINVAL;
3315         goto Bad_StoreStatus;
3316     }
3317
3318     /* Update the status of the target's vnode */
3319     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
3320                              (parentwhentargetnotdir ? parentwhentargetnotdir
3321                               : targetptr), volptr, 0);
3322
3323     /* convert the write lock to a read lock before breaking callbacks */
3324     VVnodeWriteToRead(&errorCode, targetptr);
3325     assert(!errorCode || errorCode == VSALVAGE);
3326
3327     /* Break call backs on Fid */
3328     BreakCallBack(client->host, Fid, 0);
3329
3330     /* Return the updated status back to caller */
3331     GetStatus(targetptr, OutStatus, rights, anyrights,
3332               parentwhentargetnotdir);
3333
3334   Bad_StoreStatus:
3335     /* Update and store volume/vnode and parent vnodes back */
3336     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, 
3337                      volptr, &client);
3338     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
3339     return errorCode;
3340
3341 }                               /*SAFSS_StoreStatus */
3342
3343
3344 afs_int32
3345 SRXAFS_StoreStatus(struct rx_call * acall, struct AFSFid * Fid,
3346                    struct AFSStoreStatus * InStatus,
3347                    struct AFSFetchStatus * OutStatus,
3348                    struct AFSVolSync * Sync)
3349 {
3350     afs_int32 code;
3351     struct rx_connection *tcon;
3352     struct host *thost;
3353     struct client *t_client = NULL;     /* tmp ptr to client data */
3354 #if FS_STATS_DETAILED
3355     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3356     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3357     struct timeval elapsedTime; /* Transfer time */
3358
3359     /*
3360      * Set our stats pointer, remember when the RPC operation started, and
3361      * tally the operation.
3362      */
3363     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
3364     FS_LOCK;
3365     (opP->numOps)++;
3366     FS_UNLOCK;
3367     TM_GetTimeOfDay(&opStartTime, 0);
3368 #endif /* FS_STATS_DETAILED */
3369
3370     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3371         goto Bad_StoreStatus;
3372
3373     code = SAFSS_StoreStatus(acall, Fid, InStatus, OutStatus, Sync);
3374
3375   Bad_StoreStatus:
3376     code = CallPostamble(tcon, code, thost);
3377
3378     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3379
3380 #if FS_STATS_DETAILED
3381     TM_GetTimeOfDay(&opStopTime, 0);
3382     if (code == 0) {
3383         FS_LOCK;
3384         (opP->numSuccesses)++;
3385         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3386         fs_stats_AddTo((opP->sumTime), elapsedTime);
3387         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3388         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3389             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3390         }
3391         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3392             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3393         }
3394         FS_UNLOCK;
3395     }
3396 #endif /* FS_STATS_DETAILED */
3397
3398     osi_auditU(acall, StoreStatusEvent, code, 
3399                AUD_ID, t_client ? t_client->ViceId : 0,
3400                AUD_FID, Fid, AUD_END);
3401     return code;
3402
3403 }                               /*SRXAFS_StoreStatus */
3404
3405
3406 /*
3407  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
3408  * merged in when possible.
3409  */
3410 static afs_int32
3411 SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
3412                  struct AFSFetchStatus *OutDirStatus, struct AFSVolSync *Sync)
3413 {
3414     Vnode *parentptr = 0;       /* vnode of input Directory */
3415     Vnode *parentwhentargetnotdir = 0;  /* parent for use in SetAccessList */
3416     Vnode *targetptr = 0;       /* file to be deleted */
3417     Volume *volptr = 0;         /* pointer to the volume header */
3418     AFSFid fileFid;             /* area for Fid from the directory */
3419     int errorCode = 0;          /* error code */
3420     DirHandle dir;              /* Handle for dir package I/O */
3421     struct client *client = 0;  /* pointer to client structure */
3422     afs_int32 rights, anyrights;        /* rights for this and any user */
3423     struct client *t_client;    /* tmp ptr to client data */
3424     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3425     struct rx_connection *tcon = rx_ConnectionOf(acall);
3426
3427     FidZero(&dir);
3428     /* Get ptr to client data for user Id for logging */
3429     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3430     logHostAddr.s_addr = rxr_HostOf(tcon);
3431     ViceLog(1,
3432             ("SAFS_RemoveFile %s,  Did = %u.%u.%u, Host %s:%d, Id %d\n", Name,
3433              DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3434              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3435     FS_LOCK;
3436     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
3437     FS_UNLOCK;
3438     /*
3439      * Get volume/vnode for the parent dir; caller's access rights are
3440      * also returned
3441      */
3442     if ((errorCode =
3443          GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
3444                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3445                           &rights, &anyrights))) {
3446         goto Bad_RemoveFile;
3447     }
3448     /* set volume synchronization information */
3449     SetVolumeSync(Sync, volptr);
3450
3451     /* Does the caller has delete (& write) access to the parent directory? */
3452     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
3453         goto Bad_RemoveFile;
3454     }
3455
3456     /* Actually delete the desired file */
3457     if ((errorCode =
3458          DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid, Name,
3459                       MustNOTBeDIR))) {
3460         goto Bad_RemoveFile;
3461     }
3462
3463     /* Update the vnode status of the parent dir */
3464 #if FS_STATS_DETAILED
3465     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3466                              parentptr->disk.linkCount,
3467                              client->InSameNetwork);
3468 #else
3469     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3470                              parentptr->disk.linkCount);
3471 #endif /* FS_STATS_DETAILED */
3472
3473     /* Return the updated parent dir's status back to caller */
3474     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3475
3476     /* Handle internal callback state for the parent and the deleted file */
3477     if (targetptr->disk.linkCount == 0) {
3478         /* no references left, discard entry */
3479         DeleteFileCallBacks(&fileFid);
3480         /* convert the parent lock to a read lock before breaking callbacks */
3481         VVnodeWriteToRead(&errorCode, parentptr);
3482         assert(!errorCode || errorCode == VSALVAGE);
3483     } else {
3484         /* convert the parent lock to a read lock before breaking callbacks */
3485         VVnodeWriteToRead(&errorCode, parentptr);
3486         assert(!errorCode || errorCode == VSALVAGE);
3487         /* convert the target lock to a read lock before breaking callbacks */
3488         VVnodeWriteToRead(&errorCode, targetptr);
3489         assert(!errorCode || errorCode == VSALVAGE);
3490         /* tell all the file has changed */
3491         BreakCallBack(client->host, &fileFid, 1);
3492     }
3493
3494     /* break call back on the directory */
3495     BreakCallBack(client->host, DirFid, 0);
3496
3497   Bad_RemoveFile:
3498     /* Update and store volume/vnode and parent vnodes back */
3499     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, 
3500                      volptr, &client);
3501     FidZap(&dir);
3502     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode));
3503     return errorCode;
3504
3505 }                               /*SAFSS_RemoveFile */
3506
3507
3508 afs_int32
3509 SRXAFS_RemoveFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
3510                   struct AFSFetchStatus * OutDirStatus,
3511                   struct AFSVolSync * Sync)
3512 {
3513     afs_int32 code;
3514     struct rx_connection *tcon;
3515     struct host *thost;
3516     struct client *t_client = NULL;     /* tmp ptr to client data */
3517 #if FS_STATS_DETAILED
3518     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3519     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3520     struct timeval elapsedTime; /* Transfer time */
3521
3522     /*
3523      * Set our stats pointer, remember when the RPC operation started, and
3524      * tally the operation.
3525      */
3526     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
3527     FS_LOCK;
3528     (opP->numOps)++;
3529     FS_UNLOCK;
3530     TM_GetTimeOfDay(&opStartTime, 0);
3531 #endif /* FS_STATS_DETAILED */
3532
3533     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3534         goto Bad_RemoveFile;
3535
3536     code = SAFSS_RemoveFile(acall, DirFid, Name, OutDirStatus, Sync);
3537
3538   Bad_RemoveFile:
3539     code = CallPostamble(tcon, code, thost);
3540
3541     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3542
3543 #if FS_STATS_DETAILED
3544     TM_GetTimeOfDay(&opStopTime, 0);
3545     if (code == 0) {
3546         FS_LOCK;
3547         (opP->numSuccesses)++;
3548         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3549         fs_stats_AddTo((opP->sumTime), elapsedTime);
3550         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3551         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3552             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3553         }
3554         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3555             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3556         }
3557         FS_UNLOCK;
3558     }
3559 #endif /* FS_STATS_DETAILED */
3560
3561     osi_auditU(acall, RemoveFileEvent, code, 
3562                AUD_ID, t_client ? t_client->ViceId : 0,
3563                AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3564     return code;
3565
3566 }                               /*SRXAFS_RemoveFile */
3567
3568
3569 /*
3570  * This routine is called exclusively from SRXAFS_CreateFile(), and should
3571  * be merged in when possible.
3572  */
3573 static afs_int32
3574 SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
3575                  struct AFSStoreStatus *InStatus, struct AFSFid *OutFid,
3576                  struct AFSFetchStatus *OutFidStatus,
3577                  struct AFSFetchStatus *OutDirStatus,
3578                  struct AFSCallBack *CallBack, struct AFSVolSync *Sync)
3579 {
3580     Vnode *parentptr = 0;       /* vnode of input Directory */
3581     Vnode *targetptr = 0;       /* vnode of the new file */
3582     Vnode *parentwhentargetnotdir = 0;  /* parent for use in SetAccessList */
3583     Volume *volptr = 0;         /* pointer to the volume header */
3584     int errorCode = 0;          /* error code */
3585     DirHandle dir;              /* Handle for dir package I/O */
3586     struct client *client = 0;  /* pointer to client structure */
3587     afs_int32 rights, anyrights;        /* rights for this and any user */
3588     struct client *t_client;    /* tmp ptr to client data */
3589     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3590     struct rx_connection *tcon = rx_ConnectionOf(acall);
3591
3592     FidZero(&dir);
3593
3594     /* Get ptr to client data for user Id for logging */
3595     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3596     logHostAddr.s_addr = rxr_HostOf(tcon);
3597     ViceLog(1,
3598             ("SAFS_CreateFile %s,  Did = %u.%u.%u, Host %s:%d, Id %d\n", Name,
3599              DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3600              inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3601     FS_LOCK;
3602     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
3603     FS_UNLOCK;
3604     if (!FileNameOK(Name)) {
3605         errorCode = EINVAL;
3606         goto Bad_CreateFile;
3607     }
3608
3609     /*
3610      * Get associated volume/vnode for the parent dir; caller long are
3611      * also returned
3612      */
3613     if ((errorCode =
3614          GetVolumePackage(tcon, DirFid, &volptr, &parentptr, MustBeDIR,
3615                           &parentwhentargetnotdir, &client, WRITE_LOCK,
3616                           &rights, &anyrights))) {
3617         goto Bad_CreateFile;
3618     }
3619
3620     /* set volume synchronization information */
3621     SetVolumeSync(Sync, volptr);
3622
3623     /* Can we write (and insert) onto the parent directory? */
3624     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
3625         goto Bad_CreateFile;
3626     }
3627     /* get a new vnode for the file to be created and set it up */
3628     if ((errorCode =
3629          Alloc_NewVnode(parentptr, &dir, volptr, &targetptr, Name, OutFid,
3630                         vFile, nBlocks(0)))) {
3631         goto Bad_CreateFile;
3632     }
3633
3634     /* update the status of the parent vnode */
3635 #if FS_STATS_DETAILED
3636     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3637                              parentptr->disk.linkCount,
3638                              client->InSameNetwork);
3639 #else
3640     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3641                              parentptr->disk.linkCount);
3642 #endif /* FS_STATS_DETAILED */
3643
3644     /* update the status of the new file's vnode */
3645     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
3646                              parentptr, volptr, 0);
3647
3648     /* set up the return status for the parent dir and the newly created file, and since the newly created file is owned by the creator, give it PRSFS_ADMINISTER to tell the client its the owner of the file */
3649     GetStatus(targetptr, OutFidStatus, rights | PRSFS_ADMINISTER, anyrights, parentptr);
3650     GetStatus(parentptr, OutDirStatus, rights, anyrights, 0);
3651
3652     /* convert the write lock to a read lock before breaking callbacks */
3653     VVnodeWriteToRead(&errorCode, parentptr);
3654     assert(!errorCode || errorCode == VSALVAGE);
3655
3656     /* break call back on parent dir */
3657     BreakCallBack(client->host, DirFid, 0);
3658
3659     /* Return a callback promise for the newly created file to the caller */
3660     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3661
3662   Bad_CreateFile:
3663     /* Update and store volume/vnode and parent vnodes back */
3664     (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr,
3665                            volptr, &client);
3666     FidZap(&dir);
3667     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode));
3668     return errorCode;
3669
3670 }                               /*SAFSS_CreateFile */
3671
3672
3673 afs_int32
3674 SRXAFS_CreateFile(struct rx_call * acall, struct AFSFid * DirFid, char *Name,
3675                   struct AFSStoreStatus * InStatus, struct AFSFid * OutFid,
3676                   struct AFSFetchStatus * OutFidStatus,
3677                   struct AFSFetchStatus * OutDirStatus,
3678                   struct AFSCallBack * CallBack, struct AFSVolSync * Sync)
3679 {
3680     afs_int32 code;
3681     struct rx_connection *tcon;
3682     struct host *thost;
3683     struct client *t_client = NULL;     /* tmp ptr to client data */
3684 #if FS_STATS_DETAILED
3685     struct fs_stats_opTimingData *opP;  /* Ptr to this op's timing struct */
3686     struct timeval opStartTime, opStopTime;     /* Start/stop times for RPC op */
3687     struct timeval elapsedTime; /* Transfer time */
3688
3689     /*
3690      * Set our stats pointer, remember when the RPC operation started, and
3691      * tally the operation.
3692      */
3693     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
3694     FS_LOCK;
3695     (opP->numOps)++;
3696     FS_UNLOCK;
3697     TM_GetTimeOfDay(&opStartTime, 0);
3698 #endif /* FS_STATS_DETAILED */
3699
3700     memset(OutFid, 0, sizeof(struct AFSFid));
3701
3702     if ((code = CallPreamble(acall, ACTIVECALL, &tcon, &thost)))
3703         goto Bad_CreateFile;
3704
3705     code =
3706         SAFSS_CreateFile(acall, DirFid, Name, InStatus, OutFid, OutFidStatus,
3707                          OutDirStatus, CallBack, Sync);
3708
3709   Bad_CreateFile:
3710     code = CallPostamble(tcon, code, thost);
3711
3712     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3713
3714 #if FS_STATS_DETAILED
3715     TM_GetTimeOfDay(&opStopTime, 0);
3716     if (code == 0) {
3717         FS_LOCK;
3718         (opP->numSuccesses)++;
3719         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3720         fs_stats_AddTo((opP->sumTime), elapsedTime);
3721         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3722         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3723             fs_stats_TimeAssign((opP->minTime), elapsedTime);
3724         }
3725         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3726             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3727         }
3728         FS_UNLOCK;
3729     }
3730 #endif /* FS_STATS_DETAILED */
3731
3732     osi_auditU(acall, CreateFileEvent, code, 
3733                AUD_ID, t_client ? t_client->ViceId : 0,
3734                AUD_FID, DirFid, AUD_STR, Name, AUD_FID, OutFid, AUD_END);
3735     return code;
3736
3737 }                               /*SRXAFS_CreateFile */
3738
3739
3740 /*
3741  * This routine is called exclusively from SRXAFS_Rename(), and should be
3742  * merged in when possible.
3743  */
3744 static afs_int32
3745 SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
3746              struct AFSFid *NewDirFid, char *NewName,
3747              struct AFSFetchStatus *OutOldDirStatus,
3748              struct AFSFetchStatus *OutNewDirStatus, struct AFSVolSync *Sync)
3749 {
3750     Vnode *oldvptr = 0;         /* vnode of the old Directory */
3751     Vnode *newvptr = 0;         /* vnode of the new Directory */
3752     Vnode *fileptr = 0;         /* vnode of the file to move */
3753     Vnode *newfileptr = 0;      /* vnode of the file to delete */
3754     Vnode *testvptr = 0;        /* used in directory tree walk */
3755     Vnode *parent = 0;          /* parent for use in SetAccessList */
3756     int errorCode = 0;          /* error code */
3757     int fileCode = 0;           /* used when writing Vnodes */
3758     VnodeId testnode;           /* used in directory tree walk */
3759     AFSFid fileFid;             /* Fid of file to move */
3760     AFSFid newFileFid;          /* Fid of new file */
3761     DirHandle olddir;           /* Handle for dir package I/O */
3762     DirHandle newdir;           /* Handle for dir package I/O */
3763     DirHandle filedir;          /* Handle for dir package I/O */
3764     DirHandle newfiledir;       /* Handle for dir package I/O */
3765     Volume *volptr = 0;         /* pointer to the volume header */
3766     struct client *client = 0;  /* pointer to client structure */
3767     afs_int32 rights, anyrights;        /* rights for this and any user */
3768     afs_int32 newrights;        /* rights for this user */
3769     afs_int32 newanyrights;     /* rights for any user */
3770     int doDelete;               /* deleted the rename target (ref count now 0) */
3771     int code;
3772     struct client *t_client;    /* tmp ptr to client data */
3773     struct in_addr logHostAddr; /* host ip holder for inet_ntoa */
3774     struct rx_connection *tcon = rx_ConnectionOf(acall);
3775
3776     FidZero(&olddir);
3777     FidZero(&newdir);
3778     FidZero(&filedir);
3779     FidZero(&newfiledir);
3780
3781     /* Get ptr to client data for user Id for logging */
3782     t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
3783     logHostAddr.s_addr = rxr_HostOf(tcon);
3784     ViceLog(1,
3785             ("SAFS_Rename %s    to %s,  Fid = %u.%u.%u to %u.%u.%u, Host %s:%d, Id %d\n",
3786              OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
3787              OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
3788              NewDirFid->Unique, inet_ntoa(logHostAddr), ntohs(rxr_PortOf(tcon)), t_client->ViceId));
3789     FS_LOCK;
3790     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
3791     FS_UNLOCK;
3792     if (!FileNameOK(NewName)) {
3793         errorCode = EINVAL;
3794         goto Bad_Rename;
3795     }
3796     if (OldDirFid->Volume != NewDirFid->Volume) {
3797         DFlush();
3798         errorCode = EXDEV;
3799         goto Bad_Rename;
3800     }
3801     if ((strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0)
3802         || (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0)
3803         || (strlen(NewName) == 0) || (strlen(OldName) == 0)) {
3804         DFlush();
3805         errorCode = EINVAL;
3806         goto Bad_Rename;
3807     }
3808
3809     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
3810         if ((errorCode =
3811              GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, MustBeDIR,
3812                               &parent, &client, WRITE_LOCK, &rights,
3813                               &anyrights))) {
3814             DFlush();
3815             goto Bad_Rename;
3816         }
3817         if (OldDirFid->Vnode == NewDirFid->Vnode) {
3818             newvptr = oldvptr;
3819             newrights = rights, newanyrights = anyrights;
3820         } else
3821             if ((errorCode =
3822                  GetVolumePackage(tcon, NewDirFid, &volptr, &newvptr,
3823                                   MustBeDIR, &parent, &client, WRITE_LOCK,
3824                                   &newrights, &newanyrights))) {
3825             DFlush();
3826             goto Bad_Rename;
3827         }
3828     } else {
3829         if ((errorCode =
3830              GetVolumePackage(tcon, NewDirFid, &volptr, &newvptr, MustBeDIR,
3831                               &parent, &client, WRITE_LOCK, &newrights,
3832                               &newanyrights))) {
3833             DFlush();
3834             goto Bad_Rename;
3835         }
3836         if ((errorCode =
3837              GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr, MustBeDIR,
3838                               &parent, &client, WRITE_LOCK, &rights,
3839                               &anyrights))) {
3840             DFlush();
3841             goto Bad_Rename;
3842         }
3843     }
3844
3845     /* set volume synchronization information */
3846     SetVolumeSync(Sync, volptr);
3847
3848     if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
3849         goto Bad_Rename;
3850     }
3851     if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
3852         goto Bad_Rename;
3853     }
3854
3855     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
3856      *  call to CopyOnWrite returns error, it is not necessary to revert back
3857      *  the effects of the first call because the contents of the volume is 
3858      *  not modified, it is only replicated.
3859      */
3860     if (oldvptr->disk.cloned) {
3861         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
3862         if ((errorCode = CopyOnWrite(oldvptr, volptr)))
3863             goto Bad_Rename;
3864     }
3865     SetDirHandle(&olddir, oldvptr);
3866     if (newvptr->disk.cloned) {
3867         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
3868         if ((errorCode = CopyOnWrite(newvptr, volptr)))
3869             goto Bad_Rename;
3870     }
3871
3872     SetDirHandle(&newdir, newvptr);
3873
3874     /* Lookup the file to delete its vnode */
3875     if (Lookup(&olddir, OldName, &fileFid)) {
3876         errorCode = ENOENT;
3877         goto Bad_Rename;
3878     }
3879     if (fileFid.Vnode == oldvptr->vnodeNumber
3880         || fileFid.Vnode == newvptr->vnodeNumber) {
3881         errorCode = FSERR_ELOOP;
3882         goto Bad_Rename;
3883     }
3884     fileFid.Volume = V_id(volptr);
3885     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
3886     if (errorCode != 0) {
3887         ViceLog(0,
3888                 ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n",
3889                  OldName, errorCode));
3890         VTakeOffline(volptr);
3891         goto Bad_Rename;
3892     }
3893     if (fileptr->disk.uniquifier != fileFid.Unique) {
3894         ViceLog(0,
3895                 ("SAFSS_Rename(): Old file %s uniquifier mismatch\n",
3896                  OldName));
3897         VTakeOffline(volptr);
3898         errorCode = EIO;
3899         goto Bad_Rename;
3900     }
3901
3902     if (fileptr->disk.type != vDirectory && oldvptr != newvptr
3903         && fileptr->disk.linkCount != 1) {
3904         /*
3905          * Hard links exist to this file - cannot move one of the links to
3906          * a new directory because of AFS restrictions (this is the same
3907          * reason that links cannot be made across directories, i.e.
3908          * access lists)
3909          */
3910         errorCode = EXDEV;
3911         goto Bad_Rename;
3912     }
3913
3914     /* Lookup the new file  */
3915     if (!(Lookup(&newdir, NewName, &newFileFid))) {
3916         if (readonlyServer) {
3917             errorCode = VREADONLY;
3918             goto Bad_Rename;
3919         }
3920         if (!(newrights & PRSFS_DELETE)) {
3921             errorCode = EACCES;
3922             goto Bad_Rename;
3923         }
3924         if (newFileFid.Vnode == oldvptr->vnodeNumber
3925             || newFileFid.Vnode == newvptr->vnodeNumber
3926             || newFileFid.Vnode == fileFid.Vnode) {
3927             errorCode = EINVAL;
3928             goto Bad_Rename;
3929         }
3930         newFileFid.Volume = V_id(volptr);
3931         newfileptr =
3932             VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
3933         if (errorCode != 0) {
3934             ViceLog(0,
3935                     ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n",
3936                      NewName, errorCode));
3937             VTakeOffline(volptr);
3938             goto Bad_Rename;
3939         }
3940         if (fileptr->disk.uniquifier != fileFid.Unique) {
3941             ViceLog(0,
3942                     ("SAFSS_Rename(): New file %s uniquifier mismatch\n",
3943                      NewName));
3944             VTakeOffline(volptr);
3945             errorCode = EIO;
3946             goto Bad_Rename;
3947         }
3948         SetDirHandle(&newfiledir, newfileptr);
3949         /* Now check that we're moving directories over directories properly, etc.
3950          * return proper POSIX error codes:
3951          * if fileptr is a file and new is a dir: EISDIR.
3952          * if fileptr is a dir and new is a file: ENOTDIR.
3953          * Also, dir to be removed must be empty, of course.
3954          */
3955         if (newfileptr->disk.type == vDirectory) {
3956             if (fileptr->disk.type != vDirectory) {
3957                 errorCode = EISDIR;
3958                 goto Bad_Rename;
3959             }
3960             if ((IsEmpty(&newfiledir))) {
3961                 errorCode = EEXIST;
3962                 goto Bad_Rename;
3963             }
3964         } else {
3965             if (fileptr->disk.type == vDirectory) {
3966                 errorCode = ENOTDIR;
3967                 goto Bad_Rename;
3968             }
3969         }
3970     }
3971
3972     /*
3973      * ok - now we check that the old name is not above new name in the
3974      * directory structure.  This is to prevent removing a subtree alltogether
3975      */
3976     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
3977         afs_int32 forpass = 0, vnum = 0, top = 0;
3978         for (testnode = newvptr->disk.parent; testnode != 0; forpass++) {
3979             if (testnode > vnum) vnum = testnode;
3980             if (forpass > vnum) {
3981                 errorCode = FSERR_ELOOP;
3982                 goto Bad_Rename;
3983             }
3984             if (testnode == oldvptr->vnodeNumber) {
3985                 testnode = oldvptr->disk.parent;
3986                 continue;
3987             }
3988             if ((testnode == fileptr->vnodeNumber)
3989                 || (testnode == newvptr->vnodeNumber)) {
3990                 errorCode = FSERR_ELOOP;
3991                 goto Bad_Rename;
3992             }
3993             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
3994                 errorCode = FSERR_ELOOP;
3995                 goto Bad_Rename;
3996             }
3997             if (testnode == 1) top = 1;
3998             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
3999             assert(errorCode == 0);
4000             testnode = testvptr->disk.parent;
4001             VPutVnode(&errorCode, testvptr);
4002             if ((top == 1) && (testnode != 0)) {
4003                 VTakeOffline(volptr);
4004                 ViceLog(0,
4005                         ("Volume %u now offline, must be salvaged.\n",
4006                          volptr->hashid));
4007                 errorCode = EIO;
4008                 goto Bad_Rename;
4009             }
4010             assert(errorCode == 0);
4011         }
4012     }
4013     /* Do the CopyonWrite first before modifying anything else. Copying is
4014      *  required because we may have to change entries for .. 
4015      */
4016     if ((fileptr->disk.type == vDirectory) && (fileptr->disk.cloned)) {
4017         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
4018         if ((errorCode = CopyOnWrite(fileptr, volptr)))
4019             goto Bad_Rename;
4020     }
4021
4022     /* If the new name exists already, delete it and the file it points to */
4023     doDelete = 0;
4024     if (newfileptr) {
4025         /* Delete NewName from its directory */
4026         code = Delete(&newdir, NewName);
4027         assert(code == 0);
4028
4029         /* Drop the link count */
4030         newfileptr->disk.linkCount--;
4031         if (newfileptr->disk.linkCount == 0) {  /* Link count 0 - delete */
4032             afs_fsize_t newSize;
4033             VN_GET_LEN(newSize, newfileptr);
4034             VAdjustDiskUsage((Error *) & errorCode, volptr,
4035                              (afs_sfsize_t) - nBlocks(newSize), 0);
4036             if (VN_GET_INO(newfileptr)) {
4037                 IH_REALLYCLOSE(newfileptr->handle);
4038                 errorCode =
4039                     IH_DEC(V_linkHandle(volptr), VN_GET_INO(newfileptr),
4040                            V_parentId(volptr));
4041                 IH_RELEASE(newfileptr->handle);
4042                 if (errorCode == -1) {
4043                     ViceLog(0,
4044                             ("Del: inode=%s, name=%s, errno=%d\n",
4045                              PrintInode(NULL, VN_GET_INO(newfileptr)),
4046                              NewName, errno));
4047                     if ((errno != ENOENT) && (errno != EIO)
4048                         && (errno != ENXIO))
4049                         ViceLog(0, ("Do we need to