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