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