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