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