viced-fetchdata64-should-call-common-code-in-64-mode-20011119
[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 #ifndef AFS_LINUX20_ENV
49 #include <net/if.h>
50 #include <netinet/if_ether.h>
51 #endif
52 #ifdef notdef
53 #include <nlist.h>
54 #endif
55 #endif
56 #ifdef AFS_HPUX_ENV
57 /* included early because of name conflict on IOPEN */
58 #include <sys/inode.h>
59 #ifdef IOPEN
60 #undef IOPEN
61 #endif
62 #endif /* AFS_HPUX_ENV */
63 #include <afs/stds.h>
64 #include <rx/xdr.h>
65 #include <afs/nfs.h>
66 #include <afs/assert.h>
67 #include <lwp.h>
68 #include <lock.h>
69 #include <afs/afsint.h>
70 #include <afs/vldbint.h>
71 #include <afs/errors.h>
72 #include <afs/ihandle.h>
73 #include <afs/vnode.h>
74 #include <afs/volume.h>
75 #include <afs/acl.h>
76 #include <afs/ptclient.h>
77 #include <afs/prs_fs.h>
78 #include <rx/rx.h>
79 #include <rx/rx_globals.h>
80 #include <sys/stat.h>
81 #if ! defined(AFS_SGI_ENV) && ! defined(AFS_AIX32_ENV) && ! defined(AFS_NT40_ENV) && ! defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
82 #include <sys/map.h>
83 #endif
84 #if !defined(AFS_NT40_ENV)
85 #include <unistd.h>
86 #endif
87 #if !defined(AFS_SGI_ENV) && !defined(AFS_NT40_ENV)
88 #ifdef  AFS_AIX_ENV
89 #include <sys/statfs.h>
90 #include <sys/lockf.h>
91 #else
92 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
93 #include <sys/dk.h>
94 #endif
95 #endif
96 #endif
97 #include <afs/cellconfig.h>
98 #include <afs/keys.h>
99
100 #include <afs/auth.h>
101 #include <signal.h>
102 #include <afs/partition.h>
103 #include "viced.h"
104 #include "host.h"
105 #include <afs/audit.h>
106 #include <afs/afsutil.h>
107
108 #ifdef AFS_PTHREAD_ENV
109 pthread_mutex_t fileproc_glock_mutex;
110 #endif /* AFS_PTHREAD_ENV */
111
112
113 /* Useful local defines used by this module */
114
115 #define DONTCHECK       0
116 #define MustNOTBeDIR    1
117 #define MustBeDIR       2
118
119 #define TVS_SDATA       1
120 #define TVS_SSTATUS     2
121 #define TVS_CFILE       4
122 #define TVS_SLINK       8
123 #define TVS_MKDIR       0x10
124
125 #define CHK_FETCH       0x10
126 #define CHK_FETCHDATA   0x10
127 #define CHK_FETCHACL    0x11
128 #define CHK_FETCHSTATUS 0x12
129 #define CHK_STOREDATA   0x00
130 #define CHK_STOREACL    0x01
131 #define CHK_STORESTATUS 0x02
132
133 #define OWNERREAD       0400
134 #define OWNERWRITE      0200
135 #define OWNEREXEC       0100
136 #ifdef USE_GROUP_PERMS
137 #define GROUPREAD       0040
138 #define GROUPWRITE      0020
139 #define GROUPREXEC      0010
140 #endif
141
142 /* The following errors were not defined in NT. They are given unique
143  * names here to avoid any potential collision.
144  */
145 #define FSERR_ELOOP              90
146 #define FSERR_EOPNOTSUPP        122
147 #define FSERR_ECONNREFUSED      130
148
149 #define NOTACTIVECALL   0
150 #define ACTIVECALL      1
151
152 extern struct afsconf_dir *confDir;
153 extern afs_int32 dataVersionHigh;
154
155 extern  int         SystemId;
156 extern  struct AFSCallStatistics AFSCallStats;
157 struct AFSCallStatistics AFSCallStats;
158 #if FS_STATS_DETAILED
159 struct fs_stats_FullPerfStats afs_FullPerfStats;
160 extern int AnonymousID;
161 #endif /* FS_STATS_DETAILED */
162 #if TRANSARC_VOL_STATS
163 static const char nullString[] = "";
164 #endif /* TRANSARC_VOL_STATS */
165
166 struct afs_FSStats {
167     afs_int32 NothingYet;
168 };
169
170 struct afs_FSStats afs_fsstats;
171
172 void    ResetDebug(), SetDebug(), GetStatus(), Terminate();
173 int     CopyOnWrite();          /* returns 0 on success */
174
175
176 void SetSystemStats(), SetAFSStats(), SetVolumeStats();
177 int     LogLevel = 0;
178 int     supported = 1;
179 int     Console = 0;
180 afs_int32 BlocksSpare = 1024;   /* allow 1 MB overruns */
181 afs_int32 PctSpare;
182 extern afs_int32 implicitAdminRights;
183
184 static TryLocalVLServer();
185
186 /*
187  * Externals used by the xstat code.
188  */
189 extern int VolumeCacheSize, VolumeGets, VolumeReplacements;
190 extern int CEs, CEBlocks;
191
192 extern int HTs, HTBlocks;
193
194 #ifdef AFS_SGI_XFS_IOPS_ENV
195 #include <afs/xfsattrs.h>
196 static int GetLinkCount(avp, astat)
197      Volume *avp;
198      struct stat *astat;
199 {
200     if (!strcmp("xfs", astat->st_fstype)) {
201         return (astat->st_mode & AFS_XFS_MODE_LINK_MASK);
202     }
203     else
204         return astat->st_nlink;
205 }
206 #else
207 #define GetLinkCount(V, S) (S)->st_nlink
208 #endif
209
210 afs_int32 SpareComp(avolp)
211     Volume *avolp;
212
213 {
214     register afs_int32 temp;
215
216     FS_LOCK
217     if (PctSpare) {
218         temp = V_maxquota(avolp);
219         if (temp == 0) {
220             /* no matter; doesn't check in this case */
221             FS_UNLOCK
222             return 0;
223         }
224         temp = (temp * PctSpare) / 100;
225         FS_UNLOCK
226         return temp;
227     }
228     else {
229         FS_UNLOCK
230         return BlocksSpare;
231     }
232
233 } /*SpareComp*/
234
235
236 /*
237  * Set the volume synchronization parameter for this volume.  If it changes,
238  * the Cache Manager knows that the volume must be purged from the stat cache.
239  */
240 static SetVolumeSync(async, avol)
241     register struct AFSVolSync *async;
242     register Volume *avol;
243
244 {
245     FS_LOCK
246     /* date volume instance was created */
247     if (async) {
248         if (avol)
249             async->spare1 = avol->header->diskstuff.creationDate;
250         else
251             async->spare1 = 0;
252         async->spare2 = 0;
253         async->spare3 = 0;
254         async->spare4 = 0;
255         async->spare5 = 0;
256         async->spare6 = 0;
257     }
258     FS_UNLOCK
259 } /*SetVolumeSync*/
260
261 /*
262  * This call overwrites the pointed-to rx_call with an rx_connection.  This
263  * is really bogus.  Note that this function always returns a held host, so
264  * that CallPostamble can block without the host's disappearing.
265  */
266 static CallPreamble(acall, activecall)
267     register struct rx_call **acall;
268     int activecall;
269
270 {
271     struct host *thost;
272     struct rx_connection *tconn;
273     struct client *tclient;
274     int retry_flag=1;
275     int code = 0;
276     char hoststr[16];
277     tconn = rx_ConnectionOf(*acall);
278     *acall = (struct rx_call *)tconn;       /* change it! */
279
280     H_LOCK
281 retry:
282     tclient = h_FindClient_r(tconn);
283     if (tclient->prfail == 1) { /* couldn't get the CPS */
284        if (!retry_flag) {
285           h_ReleaseClient_r(tclient);
286           ViceLog(0, ("CallPreamble: Couldn't get CPS. Fail\n"));
287           H_UNLOCK
288           return -1001;
289        }
290        retry_flag=0;    /* Retry once */
291
292        /* Take down the old connection and re-read the key file */
293        ViceLog(0, ("CallPreamble: Couldn't get CPS. Reconnect to ptserver\n"));
294        H_UNLOCK
295        code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
296        H_LOCK
297        if (code) {
298           h_ReleaseClient_r(tclient);
299           H_UNLOCK
300           ViceLog(0,("CallPreamble: couldn't reconnect to ptserver\n"));
301           return -1001;
302        }
303
304        tclient->prfail = 2;      /* Means re-eval client's cps */
305        h_ReleaseClient_r(tclient);
306        goto retry;
307     }
308
309     thost = tclient->host;
310     tclient->LastCall = thost->LastCall = FT_ApproxTime();
311     if (activecall) /* For all but "GetTime" calls */
312         thost->ActiveCall = thost->LastCall;
313
314     h_Lock_r(thost);
315     if (thost->hostFlags & HOSTDELETED) {
316       ViceLog(3,("Discarded a packet for deleted host %s\n",afs_inet_ntoa_r(thost->host,hoststr)));
317       code = VBUSY; /* raced, so retry */
318     }
319     else if (thost->hostFlags & VENUSDOWN) {
320       if (BreakDelayedCallBacks_r(thost)) {
321         ViceLog(0,("BreakDelayedCallbacks FAILED for host %s which IS UP.  Possible network or routing failure.\n",
322                 afs_inet_ntoa_r(thost->host, hoststr)));
323         if ( MultiProbeAlternateAddress_r (thost) ) {
324             ViceLog(0, ("MultiProbe failed to find new address for host %s:%d\n",
325                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
326             code = -1;
327         } else {
328             ViceLog(0, ("MultiProbe found new address for host %s:%d\n",
329                         afs_inet_ntoa_r(thost->host, hoststr), thost->port));
330             if (BreakDelayedCallBacks_r(thost)) {
331                 ViceLog(0,("BreakDelayedCallbacks FAILED AGAIN for host %s which IS UP.  Possible network or routing failure.\n",
332                         afs_inet_ntoa_r(thost->host, hoststr)));
333                 code = -1;
334             }
335         }
336       }
337     } else {
338        code =  0;
339     }
340
341     h_ReleaseClient_r(tclient);
342     h_Unlock_r(thost);
343     H_UNLOCK
344     return code;      
345
346 } /*CallPreamble*/
347
348
349 static CallPostamble(aconn)
350     register struct rx_connection *aconn;
351
352 {
353     struct host *thost;
354     struct client *tclient;
355
356     H_LOCK
357     tclient = h_FindClient_r(aconn);
358     thost = tclient->host;
359     h_ReleaseClient_r(tclient);
360     h_Release_r(thost);
361     H_UNLOCK
362
363 } /*CallPostamble*/
364
365
366 #define AFSV_BUFFERSIZE 16384 
367
368 static struct afs_buffer {
369     struct afs_buffer *next;
370 } *freeBufferList = 0;
371 static int afs_buffersAlloced = 0;
372
373
374 static FreeSendBuffer(adata)
375     register struct afs_buffer *adata;
376
377 {
378     FS_LOCK
379     afs_buffersAlloced--;
380     adata->next = freeBufferList;
381     freeBufferList = adata;
382     FS_UNLOCK
383     return 0;
384
385 } /*FreeSendBuffer*/
386
387
388 /* allocate space for sender */
389 static char *AllocSendBuffer()
390
391 {
392     register struct afs_buffer *tp;
393
394     FS_LOCK
395     afs_buffersAlloced++;
396     if (!freeBufferList) {
397         FS_UNLOCK
398         return malloc(AFSV_BUFFERSIZE);
399     }
400     tp = freeBufferList;
401     freeBufferList = tp->next;
402     FS_UNLOCK
403     return (char *) tp;
404
405 } /*AllocSendBuffer*/
406
407
408 static int VolumeOwner (client, targetptr)
409     register struct client *client;
410     register Vnode *targetptr;
411
412 {
413     afs_int32 owner = V_owner(targetptr->volumePtr);    /* get volume owner */
414
415     if (owner >= 0)
416         return (client->ViceId == owner);
417     else {
418         /* 
419          * We don't have to check for host's cps since only regular
420          * viceid are volume owners.
421          */
422         return (acl_IsAMember(owner, &client->CPS));
423     }
424
425 } /*VolumeOwner*/
426
427
428 static int VolumeRootVnode (targetptr)
429     Vnode *targetptr;
430
431 {
432     return ((targetptr->vnodeNumber == ROOTVNODE) &&
433             (targetptr->disk.uniquifier == 1));
434
435 } /*VolumeRootVnode*/
436
437
438 SRXAFS_FetchData (tcon, Fid, Pos, Len, OutStatus, CallBack, Sync)
439     struct rx_connection *tcon;         /* Rx connection handle */
440     struct AFSFid *Fid;                 /* Fid of file to fetch */
441     afs_int32 Pos, Len;                 /* Not implemented yet */
442     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
443     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
444     struct AFSVolSync *Sync;            /* synchronization info */
445
446 {
447     int code;
448
449     code = common_FetchData (tcon, Fid, Pos, Len, OutStatus,
450                                                  CallBack, Sync, 0);
451     return code;
452 }
453
454 SRXAFS_FetchData64 (tcon, Fid, Pos, Len, OutStatus, CallBack, Sync)
455     struct rx_connection *tcon;         /* Rx connection handle */
456     struct AFSFid *Fid;                 /* Fid of file to fetch */
457     afs_int64 Pos, Len;                 /* Not implemented yet */
458     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
459     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
460     struct AFSVolSync *Sync;            /* synchronization info */
461 {
462     int code;
463     afs_int32 tPos, tLen;
464
465 #ifdef AFS_64BIT_ENV
466     if (Pos + Len > 0x7fffffff)
467         return E2BIG;
468     tPos = Pos;
469     tLen = Len;
470 #else /* AFS_64BIT_ENV */
471     if (Pos.high || Len.high)
472         return E2BIG;
473     tPos = Pos.low;
474     tLen = Len.low;
475 #endif /* AFS_64BIT_ENV */
476
477     code = common_FetchData (tcon, Fid, tPos, tLen, OutStatus,
478                                                  CallBack, Sync, 1);
479     return code;
480 }
481
482 common_FetchData (tcon, Fid, Pos, Len, OutStatus, CallBack, Sync, type)
483     struct rx_connection *tcon;         /* Rx connection handle */
484     struct AFSFid *Fid;                 /* Fid of file to fetch */
485     afs_int32 Pos, Len;                 /* Not implemented yet */
486     struct AFSFetchStatus *OutStatus;   /* Returned status for Fid */
487     struct AFSCallBack *CallBack;       /* If r/w return CB for Fid */
488     struct AFSVolSync *Sync;            /* synchronization info */
489     int type;                           /* 32 bit or 64 bit call */
490
491
492     Vnode * targetptr = 0;                  /* pointer to vnode to fetch */
493     Vnode * parentwhentargetnotdir = 0;     /* parent vnode if vptr is a file */
494     Vnode   tparentwhentargetnotdir;        /* parent vnode for GetStatus */
495     int     errorCode = 0;                  /* return code to caller */
496     int     fileCode =  0;                  /* return code from vol package */
497     Volume * volptr = 0;                    /* pointer to the volume */
498     struct client *client;                  /* pointer to the client data */
499     struct rx_call *tcall;                  /* the call we're a part of */
500     afs_int32 rights, anyrights;                    /* rights for this and any user */
501     struct client *t_client;                /* tmp ptr to client data */
502     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
503 #if FS_STATS_DETAILED
504     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
505     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
506     struct timeval opStartTime,
507                    opStopTime;              /* Start/stop times for RPC op*/
508     struct timeval xferStartTime,
509                    xferStopTime;            /* Start/stop times for xfer portion*/
510     struct timeval elapsedTime;             /* Transfer time */
511     afs_int32 bytesToXfer;                          /* # bytes to xfer*/
512     afs_int32 bytesXferred;                         /* # bytes actually xferred*/
513     int readIdx;                            /* Index of read stats array to bump*/
514     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
515
516     /*
517      * Set our stats pointers, remember when the RPC operation started, and
518      * tally the operation.
519      */
520     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHDATA]);
521     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_FETCHDATA]);
522     FS_LOCK
523     (opP->numOps)++;
524     FS_UNLOCK
525     TM_GetTimeOfDay(&opStartTime, 0);
526 #endif /* FS_STATS_DETAILED */
527
528     ViceLog(1,("SRXAFS_FetchData, Fid = %u.%d.%d\n",
529             Fid->Volume, Fid->Vnode, Fid->Unique));     
530     FS_LOCK
531     AFSCallStats.FetchData++, AFSCallStats.TotalCalls++;
532     FS_UNLOCK
533
534     /* CallPreamble changes tcon from a call to a conn */
535     tcall = (struct rx_call *) tcon;
536     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
537         goto Bad_FetchData;
538
539     /* Get ptr to client data for user Id for logging */
540     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
541     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
542     ViceLog(5,("SRXAFS_FetchData, Fid = %u.%d.%d, Host %s, Id %d\n",
543             Fid->Volume, Fid->Vnode, Fid->Unique,
544             inet_ntoa(logHostAddr), t_client->ViceId)); 
545     /*
546      * Get volume/vnode for the fetched file; caller's access rights to
547      * it are also returned
548      */
549     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
550                                      DONTCHECK, &parentwhentargetnotdir,
551                                      &client, READ_LOCK, &rights, &anyrights))
552         goto Bad_FetchData;
553
554     SetVolumeSync(Sync, volptr);
555
556 #if FS_STATS_DETAILED
557     /*
558      * Remember that another read operation was performed.
559      */
560     FS_LOCK
561     if (client->InSameNetwork)
562         readIdx = VOL_STATS_SAME_NET;
563     else
564         readIdx = VOL_STATS_DIFF_NET;
565     V_stat_reads(volptr, readIdx)++;
566     if (client->ViceId != AnonymousID) {
567         V_stat_reads(volptr, readIdx+1)++;
568     }
569     FS_UNLOCK
570 #endif /* FS_STATS_DETAILED */
571
572     /* Check whether the caller has permission access to fetch the data */
573     if (errorCode = Check_PermissionRights(targetptr, client, rights,
574                                            CHK_FETCHDATA, 0)) 
575         goto Bad_FetchData;
576
577     /*
578      * Drop the read lock on the parent directory after saving the parent
579      * vnode information we need to pass to GetStatus
580      */
581     if (parentwhentargetnotdir != NULL) {
582         tparentwhentargetnotdir = *parentwhentargetnotdir;
583         VPutVnode(&fileCode, parentwhentargetnotdir);
584         assert(!fileCode || (fileCode == VSALVAGE));
585         parentwhentargetnotdir = NULL;
586     }
587
588 #if FS_STATS_DETAILED
589     /*
590      * Remember when the data transfer started.
591      */
592     TM_GetTimeOfDay(&xferStartTime, 0);
593 #endif /* FS_STATS_DETAILED */
594
595     /* actually do the data transfer */
596 #if FS_STATS_DETAILED
597     errorCode = FetchData_RXStyle(volptr, targetptr, tcall, Pos, Len, type,
598                                   &bytesToXfer, &bytesXferred);
599 #else
600     if (errorCode = FetchData_RXStyle(volptr, targetptr, tcall, Pos, Len, type))
601         goto Bad_FetchData;
602 #endif /* FS_STATS_DETAILED */
603
604 #if FS_STATS_DETAILED
605     /*
606      * At this point, the data transfer is done, for good or ill.  Remember
607      * when the transfer ended, bump the number of successes/failures, and
608      * integrate the transfer size and elapsed time into the stats.  If the
609      * operation failed, we jump to the appropriate point.
610      */
611     TM_GetTimeOfDay(&xferStopTime, 0);
612     FS_LOCK
613     (xferP->numXfers)++;
614     if (!errorCode) {
615         (xferP->numSuccesses)++;
616
617         /*
618          * Bump the xfer sum by the number of bytes actually sent, NOT the
619          * target number.
620          */
621         tot_bytesXferred += bytesXferred;
622         (xferP->sumBytes) += (tot_bytesXferred >> 10);
623         tot_bytesXferred &= 0x3FF;
624         if (bytesXferred < xferP->minBytes)
625             xferP->minBytes = bytesXferred;
626         if (bytesXferred > xferP->maxBytes)
627             xferP->maxBytes = bytesXferred;
628
629         /*
630          * Tally the size of the object.  Note: we tally the actual size,
631          * NOT the number of bytes that made it out over the wire.
632          */
633         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
634             (xferP->count[0])++;
635         else
636             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
637                 (xferP->count[1])++;
638         else
639             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
640                 (xferP->count[2])++;
641         else
642             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
643                 (xferP->count[3])++;
644         else
645             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
646                 (xferP->count[4])++;
647         else
648             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
649                 (xferP->count[5])++;
650         else
651             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
652                 (xferP->count[6])++;
653         else
654             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
655                 (xferP->count[7])++;
656         else
657             (xferP->count[8])++;
658
659         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
660         fs_stats_AddTo((xferP->sumTime), elapsedTime);
661         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
662         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
663             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
664         }
665         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
666             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
667         }
668       }
669     FS_UNLOCK
670     /*
671      * Finally, go off to tell our caller the bad news in case the
672      * fetch failed.
673      */
674     if (errorCode)
675         goto Bad_FetchData;
676 #endif /* FS_STATS_DETAILED */
677
678     /* write back  the OutStatus from the target vnode  */
679     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
680
681     /* if a r/w volume, promise a callback to the caller */
682     if (VolumeWriteable(volptr))
683         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
684     else {
685       struct AFSFid myFid;              
686       memset(&myFid, 0, sizeof(struct AFSFid));
687       myFid.Volume = Fid->Volume;
688       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
689       }
690
691 Bad_FetchData: 
692     /* Update and store volume/vnode and parent vnodes back */
693     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
694     ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); 
695     CallPostamble(tcon);
696
697 #if FS_STATS_DETAILED
698     TM_GetTimeOfDay(&opStopTime, 0);
699     if (errorCode == 0) {
700         FS_LOCK
701         (opP->numSuccesses)++;
702         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
703         fs_stats_AddTo((opP->sumTime), elapsedTime);
704         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
705         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
706             fs_stats_TimeAssign((opP->minTime), elapsedTime);
707         }
708         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
709             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
710         }
711         FS_UNLOCK
712       }
713
714 #endif /* FS_STATS_DETAILED */
715
716     osi_auditU (tcall, FetchDataEvent, errorCode, AUD_FID, Fid, AUD_END);
717     return(errorCode);
718
719 } /*SRXAFS_FetchData*/
720
721
722 SRXAFS_FetchACL (tcon, Fid, AccessList, OutStatus, Sync)
723     struct AFSVolSync *Sync;
724     struct rx_connection *tcon;         /* Rx connection handle */
725     struct AFSFid *Fid;                 /* Fid of target dir */
726     struct AFSOpaque *AccessList;       /* Returned contents of dir's ACL */
727     struct AFSFetchStatus *OutStatus;   /* Returned status for the dir */
728
729 {
730     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
731     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
732     int     errorCode = 0;              /* return error code to caller */
733     Volume * volptr = 0;                /* pointer to the volume */
734     struct client *client;              /* pointer to the client data */
735     afs_int32 rights, anyrights;                /* rights for this and any user */
736     struct rx_call *tcall = (struct rx_call *) tcon; 
737     struct client *t_client;                /* tmp ptr to client data */
738     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
739 #if FS_STATS_DETAILED
740     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
741     struct timeval opStartTime,
742                    opStopTime;              /* Start/stop times for RPC op*/
743     struct timeval elapsedTime;             /* Transfer time */
744
745     /*
746      * Set our stats pointer, remember when the RPC operation started, and
747      * tally the operation.
748      */
749     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHACL]);
750     FS_LOCK
751     (opP->numOps)++;
752     FS_UNLOCK
753     TM_GetTimeOfDay(&opStartTime, 0);
754 #endif /* FS_STATS_DETAILED */
755
756     ViceLog(1, ("SAFS_FetchACL, Fid = %u.%d.%d\n",
757             Fid->Volume, Fid->Vnode, Fid->Unique));
758     FS_LOCK
759     AFSCallStats.FetchACL++, AFSCallStats.TotalCalls++;
760     FS_UNLOCK
761     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
762         goto Bad_FetchACL;
763
764     /* Get ptr to client data for user Id for logging */
765     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
766     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
767     ViceLog(5, ("SAFS_FetchACL, Fid = %u.%d.%d, Host %s, Id %d\n",
768             Fid->Volume, Fid->Vnode, Fid->Unique,
769             inet_ntoa(logHostAddr), t_client->ViceId));
770
771     AccessList->AFSOpaque_len = 0;
772     AccessList->AFSOpaque_val = malloc(AFSOPAQUEMAX);
773
774     /*
775      * Get volume/vnode for the fetched file; caller's access rights to it
776      * are also returned
777      */
778     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
779                                      DONTCHECK, &parentwhentargetnotdir,
780                                      &client, READ_LOCK, &rights, &anyrights))
781         goto Bad_FetchACL;
782
783     SetVolumeSync(Sync, volptr);
784
785     /* Check whether we have permission to fetch the ACL */
786     if (errorCode = Check_PermissionRights(targetptr, client, rights,
787                                            CHK_FETCHACL, 0))
788         goto Bad_FetchACL;
789
790     /* Get the Access List from the dir's vnode */
791     if (errorCode = RXFetch_AccessList(targetptr, parentwhentargetnotdir,
792                                        AccessList))
793         goto Bad_FetchACL;
794
795     /* Get OutStatus back From the target Vnode  */
796     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
797
798 Bad_FetchACL: 
799     /* Update and store volume/vnode and parent vnodes back */
800     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
801     ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n",
802             errorCode, AccessList->AFSOpaque_val));
803     CallPostamble(tcon);
804
805 #if FS_STATS_DETAILED
806     TM_GetTimeOfDay(&opStopTime, 0);
807     if (errorCode == 0) {
808         FS_LOCK
809         (opP->numSuccesses)++;
810         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
811         fs_stats_AddTo((opP->sumTime), elapsedTime);
812         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
813         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
814             fs_stats_TimeAssign((opP->minTime), elapsedTime);
815         }
816         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
817             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
818         }
819         FS_UNLOCK
820       }
821
822 #endif /* FS_STATS_DETAILED */
823
824     osi_auditU (tcall, FetchACLEvent, errorCode, AUD_FID, Fid, AUD_END);
825     return errorCode;
826
827 } /*SRXAFS_FetchACL*/
828
829
830 /*
831  * This routine is called exclusively by SRXAFS_FetchStatus(), and should be
832  * merged into it when possible.
833  */
834 SAFSS_FetchStatus (tcall, Fid, OutStatus, CallBack, Sync)
835     struct rx_call *tcall;
836     struct AFSFid *Fid;                 /* Fid of target file */
837     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
838     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
839     struct AFSVolSync *Sync;            /* volume synchronization parm */
840
841 {
842     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
843     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
844     int     errorCode = 0;              /* return code to caller */
845     Volume * volptr = 0;                /* pointer to the volume */
846     struct client *client;              /* pointer to the client data */
847     afs_int32 rights, anyrights;                /* rights for this and any user */
848     struct client *t_client;            /* tmp ptr to client data */
849     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
850     struct rx_connection *tcon = rx_ConnectionOf(tcall);
851
852     /* Get ptr to client data for user Id for logging */
853     t_client = (struct client *)  rx_GetSpecific(tcon, rxcon_client_key);
854     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
855     ViceLog(1, ("SAFS_FetchStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
856             Fid->Volume, Fid->Vnode, Fid->Unique,
857             inet_ntoa(logHostAddr), t_client->ViceId));
858     FS_LOCK
859     AFSCallStats.FetchStatus++, AFSCallStats.TotalCalls++;
860     FS_UNLOCK
861     /*
862      * Get volume/vnode for the fetched file; caller's rights to it are
863      * also returned
864      */
865     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
866                                      DONTCHECK, &parentwhentargetnotdir,
867                                      &client, READ_LOCK, &rights, &anyrights))
868         goto Bad_FetchStatus;
869
870     /* set volume synchronization information */
871     SetVolumeSync(Sync, volptr);
872
873     /* Are we allowed to fetch Fid's status? */
874     if (targetptr->disk.type != vDirectory) {
875       if (errorCode = Check_PermissionRights(targetptr, client, rights,
876                                              CHK_FETCHSTATUS, 0)) {
877           if (rx_GetCallAbortCode(tcall) == errorCode) 
878               rx_SetCallAbortCode(tcall, 0);
879           goto Bad_FetchStatus;
880       }
881     }
882
883     /* set OutStatus From the Fid  */
884     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
885
886     /* If a r/w volume, also set the CallBack state */
887     if (VolumeWriteable(volptr))
888         SetCallBackStruct(AddCallBack(client->host, Fid), CallBack);
889     else {
890       struct AFSFid myFid;              
891       memset(&myFid, 0, sizeof(struct AFSFid));
892       myFid.Volume = Fid->Volume;
893       SetCallBackStruct(AddVolCallBack(client->host, &myFid), CallBack);
894       }
895
896 Bad_FetchStatus: 
897     /* Update and store volume/vnode and parent vnodes back */
898     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
899     ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); 
900     return errorCode;
901
902 } /*SAFSS_FetchStatus*/
903
904
905 SRXAFS_BulkStatus(tcon, Fids, OutStats, CallBacks, Sync)
906     struct rx_connection *tcon;
907     struct AFSCBFids *Fids;
908     struct AFSBulkStats *OutStats;
909     struct AFSCBs *CallBacks;
910     struct AFSVolSync *Sync;
911
912 {
913     register int i;
914     afs_int32 nfiles;
915     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
916     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
917     int     errorCode = 0;              /* return code to caller */
918     Volume * volptr = 0;                /* pointer to the volume */
919     struct client *client;              /* pointer to the client data */
920     afs_int32 rights, anyrights;                /* rights for this and any user */
921     register struct AFSFid *tfid;       /* file id we're dealing with now */
922     struct rx_call *tcall = (struct rx_call *) tcon; 
923 #if FS_STATS_DETAILED
924     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
925     struct timeval opStartTime,
926                    opStopTime;              /* Start/stop times for RPC op*/
927     struct timeval elapsedTime;             /* Transfer time */
928
929     /*
930      * Set our stats pointer, remember when the RPC operation started, and
931      * tally the operation.
932      */
933     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
934     FS_LOCK
935     (opP->numOps)++;
936     FS_UNLOCK
937     TM_GetTimeOfDay(&opStartTime, 0);
938 #endif /* FS_STATS_DETAILED */
939
940     ViceLog(1, ("SAFS_BulkStatus\n"));
941     FS_LOCK
942     AFSCallStats.TotalCalls++;
943     FS_UNLOCK
944
945     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
946     if (nfiles <= 0) {                  /* Sanity check */
947         errorCode = EINVAL;
948         goto Audit_and_Return;
949     }
950
951     /* allocate space for return output parameters */
952     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
953         malloc(nfiles * sizeof(struct AFSFetchStatus));
954     OutStats->AFSBulkStats_len = nfiles;
955     CallBacks->AFSCBs_val = (struct AFSCallBack *)
956         malloc(nfiles * sizeof(struct AFSCallBack));
957     CallBacks->AFSCBs_len = nfiles;
958
959     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
960         goto Bad_BulkStatus;
961
962     tfid = Fids->AFSCBFids_val;
963     for (i=0; i<nfiles; i++, tfid++) {
964         /*
965          * Get volume/vnode for the fetched file; caller's rights to it
966          * are also returned
967          */
968         if (errorCode =
969             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
970                              DONTCHECK, &parentwhentargetnotdir, &client,
971                              READ_LOCK, &rights, &anyrights))
972                 goto Bad_BulkStatus;
973         /* set volume synchronization information, but only once per call */
974         if (i == nfiles)
975             SetVolumeSync(Sync, volptr);
976
977         /* Are we allowed to fetch Fid's status? */
978         if (targetptr->disk.type != vDirectory) {
979             if (errorCode = Check_PermissionRights(targetptr, client, rights,
980                                                    CHK_FETCHSTATUS, 0)) {
981                 if (rx_GetCallAbortCode(tcall) == errorCode) 
982                     rx_SetCallAbortCode(tcall, 0);
983                 goto Bad_BulkStatus;
984             }
985         }
986
987         /* set OutStatus From the Fid  */
988         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
989                   rights, anyrights, parentwhentargetnotdir);
990
991         /* If a r/w volume, also set the CallBack state */
992         if (VolumeWriteable(volptr))
993             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
994                               &CallBacks->AFSCBs_val[i]);
995         else {
996           struct AFSFid myFid;          
997           memset(&myFid, 0, sizeof(struct AFSFid));
998           myFid.Volume = tfid->Volume;
999           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
1000                               &CallBacks->AFSCBs_val[i]);
1001         }
1002
1003         /* put back the file ID and volume */
1004         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1005         parentwhentargetnotdir = (Vnode *) 0;
1006         targetptr = (Vnode *) 0;
1007         volptr = (Volume *) 0;
1008     }
1009
1010 Bad_BulkStatus: 
1011     /* Update and store volume/vnode and parent vnodes back */
1012     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1013     CallPostamble(tcon);
1014
1015 #if FS_STATS_DETAILED
1016     TM_GetTimeOfDay(&opStopTime, 0);
1017     if (errorCode == 0) {
1018         FS_LOCK
1019         (opP->numSuccesses)++;
1020         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1021         fs_stats_AddTo((opP->sumTime), elapsedTime);
1022         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1023         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1024             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1025         }
1026         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1027             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1028         }
1029         FS_UNLOCK
1030     }   
1031
1032 #endif /* FS_STATS_DETAILED */
1033
1034 Audit_and_Return:
1035     ViceLog(2, ("SAFS_BulkStatus        returns %d\n", errorCode)); 
1036     osi_auditU (tcall, BulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
1037     return errorCode;
1038
1039 } /*SRXAFS_BulkStatus*/
1040
1041
1042 SRXAFS_InlineBulkStatus(tcon, Fids, OutStats, CallBacks, Sync)
1043     struct rx_connection *tcon;
1044     struct AFSCBFids *Fids;
1045     struct AFSBulkStats *OutStats;
1046     struct AFSCBs *CallBacks;
1047     struct AFSVolSync *Sync;
1048 {
1049     register int i;
1050     afs_int32 nfiles;
1051     Vnode * targetptr = 0;              /* pointer to vnode to fetch */
1052     Vnode * parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */
1053     int     errorCode = 0;              /* return code to caller */
1054     Volume * volptr = 0;                /* pointer to the volume */
1055     struct client *client;              /* pointer to the client data */
1056     afs_int32 rights, anyrights;                /* rights for this and any user */
1057     register struct AFSFid *tfid;       /* file id we're dealing with now */
1058     struct rx_call *tcall = (struct rx_call *) tcon; 
1059     AFSFetchStatus *tstatus;
1060 #if FS_STATS_DETAILED
1061     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1062     struct timeval opStartTime,
1063                    opStopTime;              /* Start/stop times for RPC op*/
1064     struct timeval elapsedTime;             /* Transfer time */
1065
1066     /*
1067      * Set our stats pointer, remember when the RPC operation started, and
1068      * tally the operation.
1069      */
1070     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_BULKSTATUS]);
1071     FS_LOCK
1072     (opP->numOps)++;
1073     FS_UNLOCK
1074     TM_GetTimeOfDay(&opStartTime, 0);
1075 #endif /* FS_STATS_DETAILED */
1076
1077     ViceLog(1, ("SAFS_InlineBulkStatus\n"));
1078     FS_LOCK
1079     AFSCallStats.TotalCalls++;
1080     FS_UNLOCK
1081
1082     nfiles = Fids->AFSCBFids_len;       /* # of files in here */
1083     if (nfiles <= 0) {                  /* Sanity check */
1084         errorCode = EINVAL;
1085         goto Audit_and_Return;
1086     }
1087
1088     /* allocate space for return output parameters */
1089     OutStats->AFSBulkStats_val = (struct AFSFetchStatus *)
1090         malloc(nfiles * sizeof(struct AFSFetchStatus));
1091     OutStats->AFSBulkStats_len = nfiles;
1092     CallBacks->AFSCBs_val = (struct AFSCallBack *)
1093         malloc(nfiles * sizeof(struct AFSCallBack));
1094     CallBacks->AFSCBs_len = nfiles;
1095
1096     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL)) {
1097         goto Bad_InlineBulkStatus;
1098     }
1099
1100     tfid = Fids->AFSCBFids_val;
1101     for (i=0; i<nfiles; i++, tfid++) {
1102         /*
1103          * Get volume/vnode for the fetched file; caller's rights to it
1104          * are also returned
1105          */
1106         if (errorCode =
1107             GetVolumePackage(tcon, tfid, &volptr, &targetptr,
1108                              DONTCHECK, &parentwhentargetnotdir, &client,
1109                              READ_LOCK, &rights, &anyrights)) {
1110             tstatus = &OutStats->AFSBulkStats_val[i];
1111             tstatus->errorCode = errorCode;
1112             parentwhentargetnotdir = (Vnode *) 0;
1113             targetptr = (Vnode *) 0;
1114             volptr = (Volume *) 0;
1115             continue;
1116         }
1117
1118         /* set volume synchronization information, but only once per call */
1119         if (i == nfiles)
1120             SetVolumeSync(Sync, volptr);
1121
1122         /* Are we allowed to fetch Fid's status? */
1123         if (targetptr->disk.type != vDirectory) {
1124             if (errorCode = Check_PermissionRights(targetptr, client, rights,
1125                                                    CHK_FETCHSTATUS, 0)) {
1126                 tstatus = &OutStats->AFSBulkStats_val[i];
1127                 tstatus->errorCode = errorCode;
1128                 PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1129                 parentwhentargetnotdir = (Vnode *) 0;
1130                 targetptr = (Vnode *) 0;
1131                 volptr = (Volume *) 0;
1132                 continue;
1133             }
1134         }
1135
1136         /* set OutStatus From the Fid  */
1137         GetStatus(targetptr, &OutStats->AFSBulkStats_val[i],
1138                   rights, anyrights, parentwhentargetnotdir);
1139
1140         /* If a r/w volume, also set the CallBack state */
1141         if (VolumeWriteable(volptr))
1142             SetCallBackStruct(AddBulkCallBack(client->host, tfid),
1143                               &CallBacks->AFSCBs_val[i]);
1144         else {
1145           struct AFSFid myFid;          
1146           memset(&myFid, 0, sizeof(struct AFSFid));
1147           myFid.Volume = tfid->Volume;
1148           SetCallBackStruct(AddVolCallBack(client->host, &myFid),
1149                               &CallBacks->AFSCBs_val[i]);
1150         }
1151
1152         /* put back the file ID and volume */
1153         PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr);
1154         parentwhentargetnotdir = (Vnode *) 0;
1155         targetptr = (Vnode *) 0;
1156         volptr = (Volume *) 0;
1157     }
1158
1159 Bad_InlineBulkStatus: 
1160     /* Update and store volume/vnode and parent vnodes back */
1161     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1162     CallPostamble(tcon);
1163
1164 #if FS_STATS_DETAILED
1165     TM_GetTimeOfDay(&opStopTime, 0);
1166     if (errorCode == 0) {
1167         FS_LOCK
1168         (opP->numSuccesses)++;
1169         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1170         fs_stats_AddTo((opP->sumTime), elapsedTime);
1171         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1172         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1173             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1174         }
1175         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1176             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1177         }
1178         FS_UNLOCK
1179     }   
1180
1181 #endif /* FS_STATS_DETAILED */
1182
1183 Audit_and_Return:
1184     ViceLog(2, ("SAFS_InlineBulkStatus  returns %d\n", errorCode)); 
1185     osi_auditU (tcall, InlineBulkFetchStatusEvent, errorCode, AUD_FIDS, Fids, AUD_END);
1186     return 0;
1187
1188 } /*SRXAFS_InlineBulkStatus*/
1189
1190
1191 SRXAFS_FetchStatus (tcon, Fid, OutStatus, CallBack, Sync)
1192     struct AFSVolSync *Sync;
1193     struct rx_connection *tcon;         /* Rx connection handle */
1194     struct AFSFid *Fid;                 /* Fid of target file */
1195     struct AFSFetchStatus *OutStatus;   /* Returned status for the fid */
1196     struct AFSCallBack *CallBack;       /* if r/w, callback promise for Fid */
1197
1198 {
1199     afs_int32 code;
1200     struct rx_call *tcall = (struct rx_call *) tcon; 
1201 #if FS_STATS_DETAILED
1202     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1203     struct timeval opStartTime,
1204                    opStopTime;              /* Start/stop times for RPC op*/
1205     struct timeval elapsedTime;             /* Transfer time */
1206
1207     /*
1208      * Set our stats pointer, remember when the RPC operation started, and
1209      * tally the operation.
1210      */
1211     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_FETCHSTATUS]);
1212     FS_LOCK
1213     (opP->numOps)++;
1214     FS_UNLOCK
1215     TM_GetTimeOfDay(&opStartTime, 0);
1216 #endif /* FS_STATS_DETAILED */
1217
1218     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1219         goto Bad_FetchStatus;
1220
1221     code = SAFSS_FetchStatus (tcall, Fid, OutStatus, CallBack, Sync);
1222
1223 Bad_FetchStatus:    
1224     CallPostamble(tcon);
1225
1226 #if FS_STATS_DETAILED
1227     TM_GetTimeOfDay(&opStopTime, 0);
1228     if (code == 0) {
1229         FS_LOCK
1230         (opP->numSuccesses)++;
1231         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1232         fs_stats_AddTo((opP->sumTime), elapsedTime);
1233         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1234         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1235             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1236         }
1237         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1238             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1239         }
1240         FS_UNLOCK
1241       }
1242
1243 #endif /* FS_STATS_DETAILED */
1244
1245     osi_auditU (tcall, FetchStatusEvent, code, AUD_FID, Fid, AUD_END);
1246     return code;
1247
1248 } /*SRXAFS_FetchStatus*/
1249
1250
1251 SRXAFS_StoreData (tcon, Fid, InStatus, Pos, Length, FileLength, OutStatus, Sync)
1252     struct AFSVolSync *Sync;
1253     struct rx_connection *tcon;         /* Rx connection Handle */
1254     struct AFSFid *Fid;                 /* Fid of taret file */
1255     struct AFSStoreStatus *InStatus;    /* Input Status for Fid */
1256     afs_int32 Pos;                              /* Not implemented yet */
1257     afs_int32 Length;                   /* Length of data to store */
1258     afs_int32 FileLength;                       /* Length of file after store */
1259     struct AFSFetchStatus *OutStatus;   /* Returned status for target fid */
1260
1261 {
1262     Vnode * targetptr = 0;              /* pointer to input fid */
1263     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1264     Vnode   tparentwhentargetnotdir;    /* parent vnode for GetStatus */
1265     int     errorCode = 0;              /* return code for caller */
1266     int     fileCode =  0;              /* return code from vol package */
1267     Volume * volptr = 0;                /* pointer to the volume header */
1268     struct client * client;             /* pointer to client structure */
1269     struct rx_call *tcall;              /* remember the call structure for ftp */
1270     afs_int32 rights, anyrights;                /* rights for this and any user */
1271     struct client *t_client;            /* tmp ptr to client data */
1272     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1273 #if FS_STATS_DETAILED
1274     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1275     struct fs_stats_xferData *xferP;        /* Ptr to this op's byte size struct */
1276     struct timeval opStartTime,
1277                    opStopTime;              /* Start/stop times for RPC op*/
1278     struct timeval xferStartTime,
1279                    xferStopTime;            /* Start/stop times for xfer portion*/
1280     struct timeval elapsedTime;             /* Transfer time */
1281     afs_int32 bytesToXfer;                          /* # bytes to xfer */
1282     afs_int32 bytesXferred;                         /* # bytes actually xfer */
1283     static afs_int32 tot_bytesXferred; /* shared access protected by FS_LOCK */
1284
1285     /*
1286      * Set our stats pointers, remember when the RPC operation started, and
1287      * tally the operation.
1288      */
1289     opP   = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREDATA]);
1290     xferP = &(afs_FullPerfStats.det.xferOpTimes[FS_STATS_XFERIDX_STOREDATA]);
1291     FS_LOCK
1292     (opP->numOps)++;
1293     FS_UNLOCK
1294
1295     ViceLog(1, ("StoreData: Fid = %u.%d.%d\n",
1296             Fid->Volume, Fid->Vnode, Fid->Unique));
1297     TM_GetTimeOfDay(&opStartTime, 0);
1298 #endif /* FS_STATS_DETAILED */
1299
1300     FS_LOCK
1301     AFSCallStats.StoreData++, AFSCallStats.TotalCalls++;
1302     FS_UNLOCK
1303     /* CallPreamble changes tcon from a call to a conn */
1304     tcall = (struct rx_call *) tcon;
1305     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1306         goto Bad_StoreData;
1307
1308     /* Get ptr to client data for user Id for logging */
1309     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1310     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1311     ViceLog(5, ("StoreData: Fid = %u.%d.%d, Host %s, Id %d\n",
1312             Fid->Volume, Fid->Vnode, Fid->Unique,
1313             inet_ntoa(logHostAddr), t_client->ViceId));
1314
1315     /*
1316      * Get associated volume/vnode for the stored file; caller's rights
1317      * are also returned
1318      */
1319     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1320                                      MustNOTBeDIR, &parentwhentargetnotdir,
1321                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1322         goto Bad_StoreData;
1323     }
1324
1325     /* set volume synchronization information */
1326     SetVolumeSync(Sync, volptr);
1327
1328     if ((targetptr->disk.type == vSymlink)) {
1329         /* Should we return a better error code here??? */
1330         errorCode = EISDIR;
1331         goto Bad_StoreData;
1332     }
1333
1334     /* Check if we're allowed to store the data */
1335     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1336                                            CHK_STOREDATA, InStatus)) {
1337         goto Bad_StoreData;
1338     }
1339
1340     /*
1341      * Drop the read lock on the parent directory after saving the parent
1342      * vnode information we need to pass to GetStatus
1343      */
1344     if (parentwhentargetnotdir != NULL) {
1345         tparentwhentargetnotdir = *parentwhentargetnotdir;
1346         VPutVnode(&fileCode, parentwhentargetnotdir);
1347         assert(!fileCode || (fileCode == VSALVAGE));
1348         parentwhentargetnotdir = NULL;
1349     }
1350
1351
1352
1353 #if FS_STATS_DETAILED
1354     /*
1355      * Remember when the data transfer started.
1356      */
1357     TM_GetTimeOfDay(&xferStartTime, 0);
1358 #endif /* FS_STATS_DETAILED */
1359
1360     /* Do the actual storing of the data */
1361 #if FS_STATS_DETAILED
1362     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client, tcall,
1363                                   Pos, Length, FileLength,
1364                                   (InStatus->Mask & AFS_FSYNC),
1365                                   &bytesToXfer, &bytesXferred);
1366 #else
1367     errorCode = StoreData_RXStyle(volptr, targetptr, Fid, client,
1368                                       tcall, Pos, Length, FileLength,
1369                                       (InStatus->Mask & AFS_FSYNC));
1370     if (errorCode && (!targetptr->changed_newTime))
1371             goto Bad_StoreData;
1372 #endif /* FS_STATS_DETAILED */
1373 #if FS_STATS_DETAILED
1374     /*
1375      * At this point, the data transfer is done, for good or ill.  Remember
1376      * when the transfer ended, bump the number of successes/failures, and
1377      * integrate the transfer size and elapsed time into the stats.  If the
1378      * operation failed, we jump to the appropriate point.
1379      */
1380     TM_GetTimeOfDay(&xferStopTime, 0);
1381     FS_LOCK
1382     (xferP->numXfers)++;
1383     if (!errorCode) {
1384         (xferP->numSuccesses)++;
1385
1386         /*
1387          * Bump the xfer sum by the number of bytes actually sent, NOT the
1388          * target number.
1389          */
1390         tot_bytesXferred += bytesXferred;
1391         (xferP->sumBytes) += (tot_bytesXferred >> 10);
1392         tot_bytesXferred &= 0x3FF;
1393         if (bytesXferred < xferP->minBytes)
1394             xferP->minBytes = bytesXferred;
1395         if (bytesXferred > xferP->maxBytes)
1396             xferP->maxBytes = bytesXferred;
1397       
1398         /*
1399          * Tally the size of the object.  Note: we tally the actual size,
1400          * NOT the number of bytes that made it out over the wire.
1401          */
1402         if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET0)
1403             (xferP->count[0])++;
1404         else
1405             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET1)
1406                 (xferP->count[1])++;
1407         else
1408             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET2)
1409                 (xferP->count[2])++;
1410         else
1411             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET3)
1412                 (xferP->count[3])++;
1413         else
1414             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET4)
1415                 (xferP->count[4])++;
1416         else
1417             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET5)
1418                 (xferP->count[5])++;
1419         else
1420             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET6)
1421                 (xferP->count[6])++;
1422         else
1423             if (bytesToXfer <= FS_STATS_MAXBYTES_BUCKET7)
1424                 (xferP->count[7])++;
1425         else
1426             (xferP->count[8])++;
1427       
1428         fs_stats_GetDiff(elapsedTime, xferStartTime, xferStopTime);
1429         fs_stats_AddTo((xferP->sumTime), elapsedTime);
1430         fs_stats_SquareAddTo((xferP->sqrTime), elapsedTime);
1431         if (fs_stats_TimeLessThan(elapsedTime, (xferP->minTime))) {
1432             fs_stats_TimeAssign((xferP->minTime), elapsedTime);
1433         }
1434         if (fs_stats_TimeGreaterThan(elapsedTime, (xferP->maxTime))) {
1435             fs_stats_TimeAssign((xferP->maxTime), elapsedTime);
1436         }
1437     }
1438     FS_UNLOCK
1439
1440     /*
1441      * Finally, go off to tell our caller the bad news in case the
1442      * store failed.
1443      */
1444     if (errorCode && (!targetptr->changed_newTime))
1445             goto Bad_StoreData;
1446 #endif /* FS_STATS_DETAILED */
1447
1448     /* Update the status of the target's vnode */
1449     Update_TargetVnodeStatus(targetptr, TVS_SDATA, client, InStatus, targetptr,
1450                              volptr, 0);
1451
1452     /* Get the updated File's status back to the caller */
1453     GetStatus(targetptr, OutStatus, rights, anyrights, &tparentwhentargetnotdir);
1454
1455 Bad_StoreData: 
1456     /* Update and store volume/vnode and parent vnodes back */
1457     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1458     ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode));
1459
1460     CallPostamble(tcon);
1461
1462 #if FS_STATS_DETAILED
1463     TM_GetTimeOfDay(&opStopTime, 0);
1464     if (errorCode == 0) {
1465         FS_LOCK
1466         (opP->numSuccesses)++;
1467         fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1468         fs_stats_AddTo((opP->sumTime), elapsedTime);
1469         fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1470         if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1471             fs_stats_TimeAssign((opP->minTime), elapsedTime);
1472         }
1473         if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1474             fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1475         }
1476         FS_UNLOCK
1477       }
1478 #endif /* FS_STATS_DETAILED */
1479
1480     osi_auditU (tcall, StoreDataEvent, errorCode, AUD_FID, Fid, AUD_END);
1481     return(errorCode);
1482
1483 } /*SRXAFS_StoreData*/
1484
1485 SRXAFS_StoreData64 (tcon, Fid, InStatus, Pos, Length, FileLength, OutStatus, Sync)
1486     struct AFSVolSync *Sync;
1487     struct rx_connection *tcon;         /* Rx connection Handle */
1488     struct AFSFid *Fid;                 /* Fid of taret file */
1489     struct AFSStoreStatus *InStatus;    /* Input Status for Fid */
1490     afs_int64 Pos;                              /* Not implemented yet */           afs_int64 Length;                   /* Length of data to store */
1491     afs_int64 FileLength;                       /* Length of file after store */
1492     struct AFSFetchStatus *OutStatus;   /* Returned status for target fid */
1493 {
1494     int code;
1495     afs_int32 tPos;
1496     afs_int32 tLength;
1497     afs_int32 tFileLength;
1498
1499 #ifdef AFS_64BIT_ENV
1500     if (FileLength > 0x7fffffff)
1501         return E2BIG;
1502     tPos = Pos;
1503     tLength = Length;
1504     tFileLength = FileLength;
1505 #else /* AFS_64BIT_ENV */
1506     if (FileLength.high)
1507         return E2BIG;
1508     tPos = Pos.low;
1509     tLength = Length.low;
1510     tFileLength = FileLength.low;
1511 #endif /* AFS_64BIT_ENV */
1512
1513     code = SRXAFS_StoreData (tcon, Fid, InStatus, tPos, tLength, tFileLength,
1514                                 OutStatus, Sync);
1515     return code;
1516 }
1517
1518 SRXAFS_StoreACL (tcon, Fid, AccessList, OutStatus, Sync)
1519     struct AFSVolSync *Sync;
1520     struct rx_connection *tcon;         /* Rx connection handle */
1521     struct AFSFid *Fid;                 /* Target dir's fid */
1522     struct AFSOpaque *AccessList;       /* Access List's contents */
1523     struct AFSFetchStatus *OutStatus;   /* Returned status of fid */
1524
1525 {
1526     Vnode * targetptr = 0;              /* pointer to input fid */
1527     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1528     int     errorCode = 0;              /* return code for caller */
1529     struct AFSStoreStatus InStatus;     /* Input status for fid */
1530     Volume * volptr = 0;                /* pointer to the volume header */
1531     struct client * client;             /* pointer to client structure */
1532     afs_int32 rights, anyrights;                /* rights for this and any user */
1533     struct rx_call *tcall = (struct rx_call *) tcon; 
1534     struct client *t_client;            /* tmp ptr to client data */
1535     struct in_addr logHostAddr;             /* host ip holder for inet_ntoa */
1536 #if FS_STATS_DETAILED
1537     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1538     struct timeval opStartTime,
1539                    opStopTime;              /* Start/stop times for RPC op*/
1540     struct timeval elapsedTime;             /* Transfer time */
1541
1542     /*
1543      * Set our stats pointer, remember when the RPC operation started, and
1544      * tally the operation.
1545      */
1546     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STOREACL]);
1547     FS_LOCK
1548     (opP->numOps)++;
1549     FS_UNLOCK
1550     TM_GetTimeOfDay(&opStartTime, 0);
1551 #endif /* FS_STATS_DETAILED */
1552     if (errorCode = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1553         goto Bad_StoreACL;
1554
1555     /* Get ptr to client data for user Id for logging */
1556     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1557     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1558     ViceLog(1, ("SAFS_StoreACL, Fid = %u.%d.%d, ACL=%s, Host %s, Id %d\n",
1559             Fid->Volume, Fid->Vnode, Fid->Unique, AccessList->AFSOpaque_val,
1560             inet_ntoa(logHostAddr), t_client->ViceId));
1561     FS_LOCK
1562     AFSCallStats.StoreACL++, AFSCallStats.TotalCalls++;
1563     FS_UNLOCK
1564
1565     InStatus.Mask = 0;      /* not storing any status */
1566
1567     /*
1568      * Get associated volume/vnode for the target dir; caller's rights
1569      * are also returned.
1570      */
1571     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1572                                      MustBeDIR, &parentwhentargetnotdir,
1573                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1574         goto Bad_StoreACL;
1575     }
1576
1577     /* set volume synchronization information */
1578     SetVolumeSync(Sync, volptr);
1579
1580     /* Check if we have permission to change the dir's ACL */
1581     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1582                                            CHK_STOREACL, &InStatus)) {
1583         goto Bad_StoreACL;
1584     }
1585
1586     /* Build and store the new Access List for the dir */
1587     if (errorCode = RXStore_AccessList(targetptr, AccessList)) {
1588         goto Bad_StoreACL;
1589     }
1590     
1591     targetptr->changed_newTime = 1; /* status change of directory */
1592
1593     /* convert the write lock to a read lock before breaking callbacks */
1594     VVnodeWriteToRead(&errorCode, targetptr);
1595     assert(!errorCode || errorCode == VSALVAGE);
1596
1597     /* break call backs on the directory  */
1598     BreakCallBack(client->host, Fid, 0);
1599
1600     /* Get the updated dir's status back to the caller */
1601     GetStatus(targetptr, OutStatus, rights, anyrights, (struct vnode *)0);
1602
1603 Bad_StoreACL: 
1604     /* Update and store volume/vnode and parent vnodes back */
1605     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1606     ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); 
1607     CallPostamble(tcon);
1608
1609 #if FS_STATS_DETAILED
1610     TM_GetTimeOfDay(&opStopTime, 0);
1611     if (errorCode == 0) {
1612       FS_LOCK
1613       (opP->numSuccesses)++;
1614       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1615       fs_stats_AddTo((opP->sumTime), elapsedTime);
1616       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1617       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1618         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1619       }
1620       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1621         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1622       }
1623       FS_UNLOCK
1624     }
1625 #endif /* FS_STATS_DETAILED */
1626
1627     osi_auditU (tcall, StoreACLEvent, errorCode, AUD_FID, Fid, AUD_END);
1628     return errorCode;
1629
1630 } /*SRXAFS_StoreACL*/
1631
1632
1633 /*
1634  * Note: This routine is called exclusively from SRXAFS_StoreStatus(), and
1635  * should be merged when possible.
1636  */
1637 SAFSS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync)
1638     struct rx_connection *tcon;         /* Rx connection Handle */
1639     struct AFSFid *Fid;                 /* Target file's fid */
1640     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1641     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1642     struct AFSVolSync *Sync;
1643
1644 {
1645     Vnode * targetptr = 0;              /* pointer to input fid */
1646     Vnode * parentwhentargetnotdir = 0; /* parent of Fid to get ACL */
1647     int     errorCode = 0;              /* return code for caller */
1648     Volume * volptr = 0;                /* pointer to the volume header */
1649     struct client * client;             /* pointer to client structure */
1650     afs_int32 rights, anyrights;                /* rights for this and any user */
1651     struct client *t_client;            /* tmp ptr to client data */
1652     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1653
1654     /* Get ptr to client data for user Id for logging */
1655     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1656     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1657     ViceLog(1, ("SAFS_StoreStatus,  Fid = %u.%d.%d, Host %s, Id %d\n",
1658             Fid->Volume, Fid->Vnode,    Fid->Unique,
1659             inet_ntoa(logHostAddr), t_client->ViceId));
1660     FS_LOCK
1661     AFSCallStats.StoreStatus++, AFSCallStats.TotalCalls++;
1662     FS_UNLOCK
1663     /*
1664      * Get volume/vnode for the target file; caller's rights to it are
1665      * also returned
1666      */
1667     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
1668                                      DONTCHECK, &parentwhentargetnotdir,
1669                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1670         goto Bad_StoreStatus;
1671     }
1672
1673     /* set volume synchronization information */
1674     SetVolumeSync(Sync, volptr);
1675
1676     /* Check if the caller has proper permissions to store status to Fid */
1677     if (errorCode = Check_PermissionRights(targetptr, client, rights,
1678                                            CHK_STORESTATUS, InStatus)) {
1679         goto Bad_StoreStatus;
1680     }
1681     /*
1682      * Check for a symbolic link; we can't chmod these (otherwise could
1683      * change a symlink to a mt pt or vice versa)
1684      */
1685     if (targetptr->disk.type == vSymlink && (InStatus->Mask & AFS_SETMODE)) {
1686         errorCode = EINVAL;
1687         goto Bad_StoreStatus;
1688     }
1689
1690     /* Update the status of the target's vnode */
1691     Update_TargetVnodeStatus(targetptr, TVS_SSTATUS, client, InStatus,
1692                              (parentwhentargetnotdir ?
1693                               parentwhentargetnotdir : targetptr), volptr, 0);
1694
1695     /* convert the write lock to a read lock before breaking callbacks */
1696     VVnodeWriteToRead(&errorCode, targetptr);
1697     assert(!errorCode || errorCode == VSALVAGE);
1698
1699     /* Break call backs on Fid */
1700     BreakCallBack(client->host, Fid, 0);
1701
1702     /* Return the updated status back to caller */
1703     GetStatus(targetptr, OutStatus, rights, anyrights, parentwhentargetnotdir);
1704
1705 Bad_StoreStatus: 
1706     /* Update and store volume/vnode and parent vnodes back */
1707     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
1708     ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode));
1709     return errorCode;
1710
1711 } /*SAFSS_StoreStatus*/
1712
1713
1714 SRXAFS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync)
1715     struct AFSVolSync *Sync;
1716     struct rx_connection *tcon;         /* Rx connection Handle */
1717     struct AFSFid *Fid;                 /* Target file's fid */
1718     struct AFSStoreStatus *InStatus;    /* Input status for Fid */
1719     struct AFSFetchStatus *OutStatus;   /* Output status for fid */
1720
1721 {
1722     afs_int32 code;
1723     struct rx_call *tcall = (struct rx_call *) tcon; 
1724 #if FS_STATS_DETAILED
1725     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1726     struct timeval opStartTime,
1727                    opStopTime;              /* Start/stop times for RPC op*/
1728     struct timeval elapsedTime;             /* Transfer time */
1729
1730     /*
1731      * Set our stats pointer, remember when the RPC operation started, and
1732      * tally the operation.
1733      */
1734     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_STORESTATUS]);
1735     FS_LOCK
1736     (opP->numOps)++;
1737     FS_UNLOCK
1738     TM_GetTimeOfDay(&opStartTime, 0);
1739 #endif /* FS_STATS_DETAILED */
1740
1741     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1742         goto Bad_StoreStatus;
1743
1744     code = SAFSS_StoreStatus (tcon, Fid, InStatus, OutStatus, Sync);
1745
1746 Bad_StoreStatus:
1747     CallPostamble(tcon);
1748
1749 #if FS_STATS_DETAILED
1750     TM_GetTimeOfDay(&opStopTime, 0);
1751     if (code == 0) {
1752       FS_LOCK
1753       (opP->numSuccesses)++;
1754       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1755       fs_stats_AddTo((opP->sumTime), elapsedTime);
1756       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1757       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1758         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1759       }
1760       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1761         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1762       }
1763       FS_UNLOCK
1764     }
1765
1766 #endif /* FS_STATS_DETAILED */
1767
1768     osi_auditU (tcall, StoreStatusEvent, code, AUD_FID, Fid, AUD_END);
1769     return code;
1770
1771 } /*SRXAFS_StoreStatus*/
1772
1773
1774 /*
1775  * This routine is called exclusively by SRXAFS_RemoveFile(), and should be
1776  * merged in when possible.
1777  */
1778 SAFSS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync)
1779     struct rx_connection *tcon;          /* Rx connection handle */
1780     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1781     char *Name;                          /* File name to remove */
1782     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1783     struct AFSVolSync *Sync;
1784
1785 {
1786     Vnode * parentptr = 0;              /* vnode of input Directory */
1787     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1788     Vnode * targetptr = 0;              /* file to be deleted */
1789     Volume * volptr = 0;                /* pointer to the volume header */
1790     AFSFid fileFid;                     /* area for Fid from the directory */
1791     int     errorCode = 0;              /* error code */
1792     DirHandle dir;                      /* Handle for dir package I/O */
1793     struct client * client;             /* pointer to client structure */
1794     afs_int32 rights, anyrights;                /* rights for this and any user */
1795     struct client *t_client;            /* tmp ptr to client data */
1796     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1797
1798     /* Get ptr to client data for user Id for logging */
1799     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1800     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1801     ViceLog(1, ("SAFS_RemoveFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1802             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1803             inet_ntoa(logHostAddr), t_client->ViceId));
1804     FS_LOCK
1805     AFSCallStats.RemoveFile++, AFSCallStats.TotalCalls++;
1806     FS_UNLOCK
1807     /*
1808      * Get volume/vnode for the parent dir; caller's access rights are
1809      * also returned
1810      */
1811     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1812                                      MustBeDIR, &parentwhentargetnotdir,
1813                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1814         goto Bad_RemoveFile;
1815     }
1816     /* set volume synchronization information */
1817     SetVolumeSync(Sync, volptr);
1818
1819     /* Does the caller has delete (& write) access to the parent directory? */
1820     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
1821         goto Bad_RemoveFile;
1822     }
1823
1824     /* Actually delete the desired file */
1825     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir,
1826                                  &fileFid, Name, MustNOTBeDIR)) {
1827         goto Bad_RemoveFile;
1828     }
1829
1830     /* Update the vnode status of the parent dir */
1831 #if FS_STATS_DETAILED
1832     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1833                              parentptr->disk.linkCount, client->InSameNetwork);
1834 #else
1835     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
1836                              parentptr->disk.linkCount);
1837 #endif /* FS_STATS_DETAILED */
1838
1839     /* Return the updated parent dir's status back to caller */
1840     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
1841
1842     /* Handle internal callback state for the parent and the deleted file */
1843     if (targetptr->disk.linkCount == 0) {
1844         /* no references left, discard entry */
1845         DeleteFileCallBacks(&fileFid);
1846         /* convert the parent lock to a read lock before breaking callbacks */
1847         VVnodeWriteToRead(&errorCode, parentptr);
1848         assert(!errorCode || errorCode == VSALVAGE);
1849     } else {
1850         /* convert the parent lock to a read lock before breaking callbacks */
1851         VVnodeWriteToRead(&errorCode, parentptr);
1852         assert(!errorCode || errorCode == VSALVAGE);
1853         /* convert the target lock to a read lock before breaking callbacks */
1854         VVnodeWriteToRead(&errorCode, targetptr);
1855         assert(!errorCode || errorCode == VSALVAGE);
1856         /* tell all the file has changed */
1857         BreakCallBack(client->host, &fileFid, 1);
1858     }
1859
1860     /* break call back on the directory */
1861     BreakCallBack(client->host, DirFid, 0);
1862
1863 Bad_RemoveFile: 
1864     /* Update and store volume/vnode and parent vnodes back */
1865     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
1866     ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); 
1867     return errorCode;
1868
1869 } /*SAFSS_RemoveFile*/
1870
1871
1872 SRXAFS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync)
1873     struct AFSVolSync *Sync;
1874     struct rx_connection *tcon;          /* Rx connection handle */
1875     struct AFSFid *DirFid;               /* Dir fid for file to remove */
1876     char *Name;                          /* File name to remove */
1877     struct AFSFetchStatus *OutDirStatus; /* Output status for dir fid's */
1878
1879 {
1880     afs_int32 code;
1881     struct rx_call *tcall = (struct rx_call *) tcon; 
1882 #if FS_STATS_DETAILED
1883     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
1884     struct timeval opStartTime,
1885                    opStopTime;              /* Start/stop times for RPC op*/
1886     struct timeval elapsedTime;             /* Transfer time */
1887
1888     /*
1889      * Set our stats pointer, remember when the RPC operation started, and
1890      * tally the operation.
1891      */
1892     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEFILE]);
1893     FS_LOCK
1894     (opP->numOps)++;
1895     FS_UNLOCK
1896     TM_GetTimeOfDay(&opStartTime, 0);
1897 #endif /* FS_STATS_DETAILED */
1898
1899     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
1900         goto Bad_RemoveFile;
1901
1902     code = SAFSS_RemoveFile (tcon, DirFid, Name, OutDirStatus, Sync);
1903
1904 Bad_RemoveFile:    
1905     CallPostamble(tcon);
1906
1907 #if FS_STATS_DETAILED
1908     TM_GetTimeOfDay(&opStopTime, 0);
1909     if (code == 0) {
1910       FS_LOCK
1911       (opP->numSuccesses)++;
1912       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
1913       fs_stats_AddTo((opP->sumTime), elapsedTime);
1914       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
1915       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
1916         fs_stats_TimeAssign((opP->minTime), elapsedTime);
1917       }
1918       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
1919         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
1920       }
1921       FS_UNLOCK
1922     }
1923
1924 #endif /* FS_STATS_DETAILED */
1925
1926     osi_auditU (tcall, RemoveFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
1927     return code;
1928
1929 } /*SRXAFS_RemoveFile*/
1930
1931
1932 /*
1933  * This routine is called exclusively from SRXAFS_CreateFile(), and should
1934  * be merged in when possible.
1935  */
1936 SAFSS_CreateFile (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus,
1937                  OutDirStatus, CallBack, Sync)
1938     struct rx_connection *tcon;          /* Rx connection handle */
1939     struct AFSFid *DirFid;               /* Parent Dir fid */
1940     char *Name;                          /* File name to be created */
1941     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
1942     struct AFSFid *OutFid;               /* Fid for newly created file */
1943     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
1944     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
1945     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
1946     struct AFSVolSync *Sync;
1947
1948 {
1949     Vnode * parentptr = 0;              /* vnode of input Directory */
1950     Vnode * targetptr = 0;              /* vnode of the new file */
1951     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
1952     Volume * volptr = 0;                /* pointer to the volume header */
1953     int     errorCode = 0;              /* error code */
1954     DirHandle dir;                      /* Handle for dir package I/O */
1955     struct client * client;             /* pointer to client structure */
1956     afs_int32 rights, anyrights;                /* rights for this and any user */
1957     struct client *t_client;            /* tmp ptr to client data */
1958     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
1959
1960     /* Get ptr to client data for user Id for logging */
1961     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
1962     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
1963     ViceLog(1, ("SAFS_CreateFile %s,  Did = %u.%d.%d, Host %s, Id %d\n",
1964             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
1965             inet_ntoa(logHostAddr), t_client->ViceId));
1966     FS_LOCK
1967     AFSCallStats.CreateFile++, AFSCallStats.TotalCalls++;
1968     FS_UNLOCK
1969     if (!FileNameOK(Name)) {
1970       errorCode = EINVAL;
1971       goto Bad_CreateFile;
1972     }
1973
1974     /*
1975      * Get associated volume/vnode for the parent dir; caller long are
1976      * also returned
1977      */
1978     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
1979                                      MustBeDIR, &parentwhentargetnotdir,
1980                                      &client, WRITE_LOCK, &rights, &anyrights)) {
1981         goto Bad_CreateFile;
1982     }
1983
1984     /* set volume synchronization information */
1985     SetVolumeSync(Sync, volptr);
1986
1987     /* Can we write (and insert) onto the parent directory? */
1988     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
1989         goto Bad_CreateFile;
1990     }
1991     /* get a new vnode for the file to be created and set it up */
1992     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
1993                                    Name, OutFid, vFile, nBlocks(0))) {
1994         goto Bad_CreateFile;
1995     }
1996
1997     /* update the status of the parent vnode */
1998 #if FS_STATS_DETAILED
1999     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2000                              parentptr->disk.linkCount, client->InSameNetwork);
2001 #else
2002     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2003                              parentptr->disk.linkCount);
2004 #endif /* FS_STATS_DETAILED */
2005
2006     /* update the status of the new file's vnode */
2007     Update_TargetVnodeStatus(targetptr, TVS_CFILE, client, InStatus,
2008                              parentptr, volptr, 0);
2009
2010     /* set up the return status for the parent dir and the newly created file */
2011     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2012     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
2013
2014     /* convert the write lock to a read lock before breaking callbacks */
2015     VVnodeWriteToRead(&errorCode, parentptr);
2016     assert(!errorCode || errorCode == VSALVAGE);
2017     
2018     /* break call back on parent dir */
2019     BreakCallBack(client->host, DirFid, 0);
2020
2021     /* Return a callback promise for the newly created file to the caller */
2022     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
2023
2024 Bad_CreateFile:
2025     /* Update and store volume/vnode and parent vnodes back */
2026     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2027     ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); 
2028     return errorCode;
2029
2030 } /*SAFSS_CreateFile*/
2031
2032
2033 SRXAFS_CreateFile (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
2034     struct AFSVolSync *Sync;
2035     struct rx_connection *tcon;          /* Rx connection handle */
2036     struct AFSFid *DirFid;               /* Parent Dir fid */
2037     char *Name;                          /* File name to be created */
2038     struct AFSStoreStatus *InStatus;     /* Input status for newly created file */
2039     struct AFSFid *OutFid;               /* Fid for newly created file */
2040     struct AFSFetchStatus *OutFidStatus; /* Output status for new file */
2041     struct AFSFetchStatus *OutDirStatus; /* Ouput status for the parent dir */
2042     struct AFSCallBack *CallBack;        /* Return callback promise for new file */
2043
2044 {
2045     afs_int32 code;
2046     struct rx_call *tcall = (struct rx_call *) tcon; 
2047 #if FS_STATS_DETAILED
2048     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2049     struct timeval opStartTime,
2050                    opStopTime;              /* Start/stop times for RPC op*/
2051     struct timeval elapsedTime;             /* Transfer time */
2052
2053     /*
2054      * Set our stats pointer, remember when the RPC operation started, and
2055      * tally the operation.
2056      */
2057     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_CREATEFILE]);
2058     FS_LOCK
2059     (opP->numOps)++;
2060     FS_UNLOCK
2061     TM_GetTimeOfDay(&opStartTime, 0);
2062 #endif /* FS_STATS_DETAILED */
2063
2064     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2065         goto Bad_CreateFile;
2066
2067     code = SAFSS_CreateFile (tcon, DirFid, Name, InStatus, OutFid,
2068                             OutFidStatus, OutDirStatus, CallBack, Sync);
2069
2070 Bad_CreateFile:    
2071     CallPostamble(tcon);
2072
2073 #if FS_STATS_DETAILED
2074     TM_GetTimeOfDay(&opStopTime, 0);
2075     if (code == 0) {
2076       FS_LOCK
2077       (opP->numSuccesses)++;
2078       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2079       fs_stats_AddTo((opP->sumTime), elapsedTime);
2080       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2081       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2082         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2083       }
2084       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2085         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2086       }
2087       FS_UNLOCK
2088     }
2089 #endif /* FS_STATS_DETAILED */
2090
2091     osi_auditU (tcall, CreateFileEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2092     return code;
2093
2094 } /*SRXAFS_CreateFile*/
2095
2096
2097 /*
2098  * This routine is called exclusively from SRXAFS_Rename(), and should be
2099  * merged in when possible.
2100  */
2101 SAFSS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus,
2102              OutNewDirStatus, Sync)
2103     struct rx_connection *tcon;             /* Rx connection handle */
2104     struct AFSFid *OldDirFid;               /* From parent dir's fid */
2105     char *OldName;                          /* From file name */
2106     struct AFSFid *NewDirFid;               /* To parent dir's fid */
2107     char *NewName;                          /* To new file name */
2108     struct AFSFetchStatus *OutOldDirStatus; /* Output status for From parent dir */
2109     struct AFSFetchStatus *OutNewDirStatus; /* Output status for To parent dir */
2110     struct AFSVolSync *Sync;
2111
2112 {
2113     Vnode * oldvptr = 0;        /* vnode of the old Directory */
2114     Vnode * newvptr = 0;        /* vnode of the new Directory */
2115     Vnode * fileptr = 0;        /* vnode of the file to move */
2116     Vnode * newfileptr = 0;     /* vnode of the file to delete */
2117     Vnode * testvptr = 0;       /* used in directory tree walk */
2118     Vnode * parent = 0;         /* parent for use in SetAccessList */
2119     int     errorCode = 0;      /* error code */
2120     int     fileCode = 0;       /* used when writing Vnodes */
2121     VnodeId testnode;           /* used in directory tree walk */
2122     AFSFid fileFid;             /* Fid of file to move */
2123     AFSFid newFileFid;          /* Fid of new file */
2124     DirHandle olddir;           /* Handle for dir package I/O */
2125     DirHandle newdir;           /* Handle for dir package I/O */
2126     DirHandle filedir;          /* Handle for dir package I/O */
2127     DirHandle newfiledir;       /* Handle for dir package I/O */
2128     Volume * volptr = 0;        /* pointer to the volume header */
2129     struct client * client;     /* pointer to client structure */
2130     afs_int32 rights, anyrights;        /* rights for this and any user */
2131     afs_int32 newrights;                /* rights for this user */
2132     afs_int32 newanyrights;             /* rights for any user */
2133     int doDelete;               /* deleted the rename target (ref count now 0) */
2134     int code;
2135     struct client *t_client;            /* tmp ptr to client data */
2136     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2137
2138     /* Get ptr to client data for user Id for logging */
2139     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2140     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2141     ViceLog(1, ("SAFS_Rename %s to %s,  Fid = %u.%d.%d to %u.%d.%d, Host %s, Id %d\n",
2142             OldName, NewName, OldDirFid->Volume, OldDirFid->Vnode,
2143             OldDirFid->Unique, NewDirFid->Volume, NewDirFid->Vnode,
2144             NewDirFid->Unique,
2145             inet_ntoa(logHostAddr), t_client->ViceId));
2146     FS_LOCK
2147     AFSCallStats.Rename++, AFSCallStats.TotalCalls++;
2148     FS_UNLOCK
2149     if (!FileNameOK(NewName)) {
2150         errorCode = EINVAL;
2151         goto Bad_Rename;
2152     }
2153     if (OldDirFid->Volume != NewDirFid->Volume) {
2154         DFlush();
2155         errorCode = EXDEV;
2156         goto Bad_Rename;
2157     }
2158     if ( (strcmp(OldName, ".") == 0) || (strcmp(OldName, "..") == 0) ||
2159          (strcmp(NewName, ".") == 0) || (strcmp(NewName, "..") == 0) || 
2160          (strlen(NewName) == 0) || (strlen(OldName) == 0)  ) {
2161         DFlush();
2162         errorCode = EINVAL;
2163         goto Bad_Rename;
2164     }
2165
2166     if (OldDirFid->Vnode <= NewDirFid->Vnode) {
2167         if  (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr,
2168                                           &oldvptr, MustBeDIR, &parent,
2169                                           &client, WRITE_LOCK, &rights,
2170                                           &anyrights)) {
2171             DFlush();
2172             goto Bad_Rename;
2173         }
2174         if (OldDirFid->Vnode == NewDirFid->Vnode) {
2175             newvptr = oldvptr;
2176             newrights = rights, newanyrights = anyrights;
2177         }
2178         else
2179             if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2180                                              &newvptr, MustBeDIR, &parent,
2181                                              &client, WRITE_LOCK, &newrights,
2182                                              &newanyrights)) {
2183                 DFlush();
2184                 goto Bad_Rename;
2185             }
2186     }
2187     else {
2188         if (errorCode = GetVolumePackage(tcon, NewDirFid, &volptr,
2189                                          &newvptr, MustBeDIR, &parent,
2190                                          &client, WRITE_LOCK, &newrights,
2191                                          &newanyrights)) {
2192             DFlush();
2193             goto Bad_Rename;
2194         }
2195         if (errorCode = GetVolumePackage(tcon, OldDirFid, &volptr, &oldvptr,
2196                                          MustBeDIR, &parent, &client, WRITE_LOCK,
2197                                          &rights, &anyrights)) {
2198             DFlush();
2199             goto Bad_Rename;
2200         }
2201     }
2202
2203     /* set volume synchronization information */
2204     SetVolumeSync(Sync, volptr);
2205
2206     if (errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE)) {
2207         goto Bad_Rename;
2208     }
2209     if (errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT)) {
2210         goto Bad_Rename;
2211     }
2212
2213     /* The CopyOnWrite might return ENOSPC ( disk full). Even if the second
2214     *  call to CopyOnWrite returns error, it is not necessary to revert back
2215     *  the effects of the first call because the contents of the volume is 
2216     *  not modified, it is only replicated.
2217     */
2218     if (oldvptr->disk.cloned)
2219     {
2220         ViceLog(25, ("Rename : calling CopyOnWrite on  old dir\n"));
2221          if ( errorCode = CopyOnWrite(oldvptr, volptr) )
2222                 goto Bad_Rename;
2223     }
2224     SetDirHandle(&olddir, oldvptr);
2225     if (newvptr->disk.cloned)
2226     {
2227         ViceLog(25, ("Rename : calling CopyOnWrite on  new dir\n"));
2228         if ( errorCode = CopyOnWrite(newvptr, volptr) )
2229                 goto Bad_Rename;        
2230     }
2231
2232     SetDirHandle(&newdir, newvptr);
2233
2234     /* Lookup the file to delete its vnode */
2235     if (Lookup(&olddir, OldName, &fileFid)) {
2236         errorCode = ENOENT;
2237         goto Bad_Rename;
2238     }
2239     if (fileFid.Vnode == oldvptr->vnodeNumber ||
2240         fileFid.Vnode == newvptr->vnodeNumber) {
2241         errorCode = FSERR_ELOOP;
2242         goto Bad_Rename;
2243     }
2244     fileFid.Volume = V_id(volptr);
2245     fileptr = VGetVnode(&errorCode, volptr, fileFid.Vnode, WRITE_LOCK);
2246     if (errorCode != 0) {
2247         ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for old file %s, code %d\n", OldName, errorCode));
2248         VTakeOffline (volptr);
2249         goto Bad_Rename;
2250     }
2251     if (fileptr->disk.uniquifier != fileFid.Unique) {
2252         ViceLog (0, ("SAFSS_Rename(): Old file %s uniquifier mismatch\n", OldName));
2253         VTakeOffline (volptr);
2254         errorCode = EIO;
2255         goto Bad_Rename;
2256     }
2257
2258     if (fileptr->disk.type != vDirectory &&
2259         oldvptr != newvptr &&
2260         fileptr->disk.linkCount != 1) {
2261         /*
2262          * Hard links exist to this file - cannot move one of the links to
2263          * a new directory because of AFS restrictions (this is the same
2264          * reason that links cannot be made across directories, i.e.
2265          * access lists)
2266          */
2267         errorCode = EXDEV;
2268         goto Bad_Rename;
2269     }
2270
2271     /* Lookup the new file  */
2272     if (!(Lookup(&newdir, NewName, &newFileFid))) {
2273         if (!(newrights & PRSFS_DELETE)) {
2274             errorCode = EACCES;
2275             goto Bad_Rename;
2276         }
2277         if (newFileFid.Vnode == oldvptr->vnodeNumber ||
2278                 newFileFid.Vnode == newvptr->vnodeNumber ||
2279                 newFileFid.Vnode == fileFid.Vnode) {
2280             errorCode = EINVAL;
2281             goto Bad_Rename;
2282         }
2283         newFileFid.Volume = V_id(volptr);
2284         newfileptr = VGetVnode(&errorCode, volptr, newFileFid.Vnode, WRITE_LOCK);
2285         if (errorCode != 0) {
2286             ViceLog (0, ("SAFSS_Rename(): Error in VGetVnode() for new file %s, code %d\n", NewName, errorCode));
2287             VTakeOffline (volptr);
2288             goto Bad_Rename;
2289         }
2290         if (fileptr->disk.uniquifier != fileFid.Unique) {
2291             ViceLog (0, ("SAFSS_Rename(): New file %s uniquifier mismatch\n", NewName));
2292             VTakeOffline (volptr);
2293             errorCode = EIO;
2294             goto Bad_Rename;
2295         }
2296         SetDirHandle(&newfiledir, newfileptr);
2297         /* Now check that we're moving directories over directories properly, etc.
2298          * return proper POSIX error codes:
2299          * if fileptr is a file and new is a dir: EISDIR.
2300          * if fileptr is a dir and new is a file: ENOTDIR.
2301          * Also, dir to be removed must be empty, of course.
2302          */
2303         if (newfileptr->disk.type == vDirectory) {
2304             if (fileptr->disk.type != vDirectory) {
2305                 errorCode = EISDIR;
2306                 goto Bad_Rename;
2307             }
2308             if ((IsEmpty(&newfiledir))) {
2309                 errorCode = EEXIST;
2310                 goto Bad_Rename;
2311             }
2312         }
2313         else {
2314             if (fileptr->disk.type == vDirectory) {
2315                 errorCode = ENOTDIR;
2316                 goto Bad_Rename;
2317             }
2318         }
2319     }
2320
2321     /*
2322      * ok - now we check that the old name is not above new name in the
2323      * directory structure.  This is to prevent removing a subtree alltogether
2324      */
2325     if ((oldvptr != newvptr) && (fileptr->disk.type == vDirectory)) {
2326         for (testnode = newvptr->disk.parent; testnode != 0;) {
2327             if (testnode == oldvptr->vnodeNumber) {
2328                 testnode = oldvptr->disk.parent;
2329                 continue;
2330             }
2331             if ((testnode == fileptr->vnodeNumber) ||
2332                 (testnode == newvptr->vnodeNumber)) {
2333                 errorCode = FSERR_ELOOP;
2334                 goto Bad_Rename;
2335             }
2336             if ((newfileptr) && (testnode == newfileptr->vnodeNumber)) {
2337                 errorCode = FSERR_ELOOP;
2338                 goto Bad_Rename;
2339             }
2340             testvptr = VGetVnode(&errorCode, volptr, testnode, READ_LOCK);
2341             assert(errorCode == 0);
2342             testnode = testvptr->disk.parent;
2343             VPutVnode(&errorCode, testvptr);
2344             assert(errorCode == 0);
2345         }
2346     }
2347     /* Do the CopyonWrite first before modifying anything else. Copying is
2348      *  required because we may have to change entries for .. 
2349      */
2350     if ((fileptr->disk.type == vDirectory ) && (fileptr->disk.cloned) )
2351     {
2352         ViceLog(25, ("Rename : calling CopyOnWrite on  target dir\n"));
2353         if ( errorCode = CopyOnWrite(fileptr, volptr) )
2354                 goto Bad_Rename;
2355     }
2356
2357     /* If the new name exists already, delete it and the file it points to */
2358     doDelete = 0;
2359     if (newfileptr) {
2360         /* Delete NewName from its directory */
2361         code = Delete(&newdir, NewName);
2362         assert(code == 0);
2363
2364         /* Drop the link count */
2365         newfileptr->disk.linkCount--;
2366         if (newfileptr->disk.linkCount == 0) {      /* Link count 0 - delete */
2367             VAdjustDiskUsage(&errorCode, volptr,
2368                              -(int)nBlocks(newfileptr->disk.length), 0);
2369             if (VN_GET_INO(newfileptr)) {
2370                 IH_REALLYCLOSE(newfileptr->handle);
2371                 errorCode = IH_DEC(V_linkHandle(volptr),
2372                                  VN_GET_INO(newfileptr),
2373                                  V_parentId(volptr));
2374                 IH_RELEASE(newfileptr->handle);
2375                 if (errorCode == -1) {
2376                     ViceLog(0, ("Del: inode=%d, name=%s, errno=%d\n",
2377                                 PrintInode(NULL, VN_GET_INO(newfileptr)),
2378                                 NewName, errno));
2379                     if ((errno != ENOENT) && (errno != EIO) && (errno != ENXIO))
2380                         ViceLog(0, ("Do we need to fsck?"));
2381                 } 
2382             }
2383             VN_SET_INO(newfileptr, (Inode)0);
2384             newfileptr->delete = 1;         /* Mark NewName vnode to delete */
2385             doDelete = 1;
2386         } else {
2387             /* Link count did not drop to zero.
2388              * Mark NewName vnode as changed - updates stime.
2389              */
2390             newfileptr->changed_newTime = 1;
2391         }
2392     }
2393     
2394     /*
2395      * If the create below fails, and the delete above worked, we have
2396      * removed the new name and not replaced it.  This is not very likely,
2397      * but possible.  We could try to put the old file back, but it is
2398      * highly unlikely that it would work since it would involve issuing
2399      * another create.
2400      */
2401     if (errorCode = Create(&newdir,(char *) NewName, &fileFid))
2402         goto Bad_Rename;
2403
2404     /* Delete the old name */
2405     assert(Delete(&olddir,(char *) OldName) == 0);
2406
2407     /* if the directory length changes, reflect it in the statistics */
2408 #if FS_STATS_DETAILED
2409     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2410                              oldvptr->disk.linkCount, client->InSameNetwork);
2411     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2412                              newvptr->disk.linkCount, client->InSameNetwork);
2413 #else
2414     Update_ParentVnodeStatus(oldvptr, volptr, &olddir, client->ViceId,
2415                              oldvptr->disk.linkCount);
2416     Update_ParentVnodeStatus(newvptr, volptr, &newdir, client->ViceId,
2417                              newvptr->disk.linkCount);
2418 #endif /* FS_STATS_DETAILED */
2419
2420     if (oldvptr == newvptr)
2421         oldvptr->disk.dataVersion--;    /* Since it was bumped by 2! */
2422
2423     fileptr->disk.parent = newvptr->vnodeNumber;
2424     fileptr->changed_newTime = 1;       /* status change of moved file */
2425
2426     /* if we are dealing with a rename of a directory */
2427     if (fileptr->disk.type == vDirectory) {
2428         assert(!fileptr->disk.cloned);          
2429         SetDirHandle(&filedir, fileptr);
2430         /* fix .. to point to the correct place */
2431         Delete(&filedir, ".."); /* No assert--some directories may be bad */
2432         assert(Create(&filedir, "..", NewDirFid) == 0);
2433         fileptr->disk.dataVersion++;
2434         /* if the parent directories are different the link counts have to be   */
2435         /* changed due to .. in the renamed directory */
2436         if (oldvptr != newvptr) {
2437             oldvptr->disk.linkCount--;
2438             newvptr->disk.linkCount++;
2439         }
2440     }
2441
2442     /* set up return status */
2443     GetStatus(oldvptr, OutOldDirStatus, rights, anyrights, (struct vnode *)0);
2444     GetStatus(newvptr, OutNewDirStatus, newrights, newanyrights, (struct vnode *)0);
2445     if (newfileptr && doDelete) {
2446         DeleteFileCallBacks(&newFileFid);       /* no other references */
2447     }
2448
2449     DFlush();
2450
2451     /* convert the write locks to a read locks before breaking callbacks */
2452     VVnodeWriteToRead(&errorCode, newvptr);
2453     assert(!errorCode || errorCode == VSALVAGE);
2454     if (oldvptr != newvptr) {
2455         VVnodeWriteToRead(&errorCode, oldvptr);
2456         assert(!errorCode || errorCode == VSALVAGE);
2457     }
2458     if (newfileptr && !doDelete) {
2459         /* convert the write lock to a read lock before breaking callbacks */
2460         VVnodeWriteToRead(&errorCode, newfileptr);
2461         assert(!errorCode || errorCode == VSALVAGE);
2462     }
2463
2464     /* break call back on NewDirFid, OldDirFid, NewDirFid and newFileFid  */
2465     BreakCallBack(client->host, NewDirFid, 0);
2466     if (oldvptr != newvptr) {
2467         BreakCallBack(client->host, OldDirFid, 0);
2468         if (fileptr->disk.type == vDirectory) /* if a dir moved, .. changed */
2469             BreakCallBack(client->host, &fileFid, 0);
2470     }
2471     if (newfileptr) {
2472         /* Note:  it is not necessary to break the callback */
2473         if (doDelete)
2474             DeleteFileCallBacks(&newFileFid);   /* no other references */
2475         else
2476             /* other's still exist (with wrong link count) */
2477             BreakCallBack(client->host, &newFileFid, 1);
2478     }
2479
2480 Bad_Rename: 
2481     if (newfileptr) {
2482         VPutVnode(&fileCode, newfileptr);
2483         assert(fileCode == 0);
2484     }
2485     PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr? newvptr : 0),
2486                      oldvptr, volptr);
2487     ViceLog(2, ("SAFS_Rename returns %d\n", errorCode));
2488     return errorCode;
2489
2490 } /*SAFSS_Rename*/
2491
2492
2493 SRXAFS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName, OutOldDirStatus, OutNewDirStatus, Sync)
2494     struct AFSVolSync *Sync;
2495     struct rx_connection *tcon;              /* Rx connection handle */
2496     struct AFSFid *OldDirFid;                /* From parent dir's fid */
2497     char *OldName;                           /* From file name */
2498     struct AFSFid *NewDirFid;                /* To parent dir's fid */
2499     char *NewName;                           /* To new file name */
2500     struct AFSFetchStatus *OutOldDirStatus;  /* Output status for From parent dir */
2501     struct AFSFetchStatus *OutNewDirStatus;  /* Output status for To parent dir */
2502
2503 {
2504     afs_int32 code;
2505     struct rx_call *tcall = (struct rx_call *) tcon; 
2506 #if FS_STATS_DETAILED
2507     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2508     struct timeval opStartTime,
2509                    opStopTime;              /* Start/stop times for RPC op*/
2510     struct timeval elapsedTime;             /* Transfer time */
2511
2512     /*
2513      * Set our stats pointer, remember when the RPC operation started, and
2514      * tally the operation.
2515      */
2516     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_RENAME]);
2517     FS_LOCK
2518     (opP->numOps)++;
2519     FS_UNLOCK
2520     TM_GetTimeOfDay(&opStartTime, 0);
2521 #endif /* FS_STATS_DETAILED */
2522
2523     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2524         goto Bad_Rename;
2525
2526     code = SAFSS_Rename (tcon, OldDirFid, OldName, NewDirFid, NewName,
2527                          OutOldDirStatus, OutNewDirStatus, Sync);
2528
2529 Bad_Rename:    
2530     CallPostamble(tcon);
2531
2532 #if FS_STATS_DETAILED
2533     TM_GetTimeOfDay(&opStopTime, 0);
2534     if (code == 0) {
2535       FS_LOCK
2536       (opP->numSuccesses)++;
2537       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2538       fs_stats_AddTo((opP->sumTime), elapsedTime);
2539       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2540       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2541         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2542       }
2543       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2544         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2545       }
2546       FS_UNLOCK
2547     }
2548
2549 #endif /* FS_STATS_DETAILED */
2550
2551     osi_auditU (tcall, RenameFileEvent, code, AUD_FID, OldDirFid, AUD_STR, OldName, AUD_FID, NewDirFid, AUD_STR, NewName, AUD_END);
2552     return code;
2553
2554 } /*SRXAFS_Rename*/
2555
2556
2557 /*
2558  * This routine is called exclusively by SRXAFS_Symlink(), and should be
2559  * merged into it when possible.
2560  */
2561 SAFSS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2562     struct rx_connection *tcon;          /* Rx connection handle */
2563     struct AFSFid *DirFid;               /* Parent dir's fid */
2564     char *Name;                          /* File name to create */
2565     char *LinkContents;                  /* Contents of the new created file */
2566     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2567     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2568     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2569     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2570     struct AFSVolSync *Sync;             /* volume synchronization information */
2571
2572 {
2573     Vnode * parentptr = 0;              /* vnode of input Directory */
2574     Vnode * targetptr = 0;              /* vnode of the new link */
2575     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2576     int     errorCode = 0;              /* error code */
2577     int code = 0;
2578     DirHandle dir;                      /* Handle for dir package I/O */
2579     Volume * volptr = 0;                /* pointer to the volume header */
2580     struct client * client;             /* pointer to client structure */
2581     afs_int32 rights, anyrights, fd;    /* rights for this and any user */
2582     struct client *t_client;            /* tmp ptr to client data */
2583     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2584     FdHandle_t *fdP;
2585
2586     /* Get ptr to client data for user Id for logging */
2587     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2588     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2589     ViceLog(1, ("SAFS_Symlink %s to %s,  Did = %u.%d.%d, Host %s, Id %d\n", Name,
2590             LinkContents, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2591             inet_ntoa(logHostAddr), t_client->ViceId));
2592     FS_LOCK
2593     AFSCallStats.Symlink++, AFSCallStats.TotalCalls++;
2594     FS_UNLOCK
2595     if (!FileNameOK(Name)) {
2596         errorCode = EINVAL;
2597         goto Bad_SymLink;
2598     }
2599
2600     /*
2601      * Get the vnode and volume for the parent dir along with the caller's
2602      * rights to it
2603      */
2604     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2605                                      MustBeDIR, &parentwhentargetnotdir,
2606                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2607         goto Bad_SymLink;
2608     }
2609
2610     /* set volume synchronization information */
2611     SetVolumeSync(Sync, volptr);
2612
2613     /* Does the caller has insert (and write) access to the parent directory? */
2614     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2615         goto Bad_SymLink;
2616     }
2617
2618     /*
2619      * If we're creating a mount point (any x bits clear), we must have
2620      * administer access to the directory, too.  Always allow sysadmins
2621      * to do this.
2622      */
2623     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
2624         /*
2625          * We have a mountpoint, 'cause we're trying to set the Unix mode
2626          * bits to something with some x bits missing (default mode bits
2627          * if AFS_SETMODE is false is 0777)
2628          */
2629         if (VanillaUser(client) && !(rights & PRSFS_ADMINISTER)) {
2630             errorCode = EACCES;
2631             goto Bad_SymLink;
2632         }
2633     }
2634  
2635     /* get a new vnode for the symlink and set it up */
2636     if (errorCode = Alloc_NewVnode(parentptr, &dir, volptr, &targetptr,
2637                                    Name, OutFid, vSymlink,
2638                                    nBlocks(strlen((char *) LinkContents)))) {
2639         goto Bad_SymLink;
2640     }
2641
2642     /* update the status of the parent vnode */
2643 #if FS_STATS_DETAILED
2644     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2645                              parentptr->disk.linkCount, client->InSameNetwork);
2646 #else
2647     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2648                              parentptr->disk.linkCount);
2649 #endif /* FS_STATS_DETAILED */
2650
2651     /* update the status of the new symbolic link file vnode */
2652     Update_TargetVnodeStatus(targetptr, TVS_SLINK, client, InStatus, parentptr,
2653                              volptr, strlen((char *)LinkContents));
2654
2655     /* Write the contents of the symbolic link name into the target inode */
2656     fdP = IH_OPEN(targetptr->handle);
2657     assert(fdP != NULL);
2658     assert(FDH_WRITE(fdP, (char *) LinkContents, strlen((char *) LinkContents)) == strlen((char *) LinkContents));
2659     FDH_CLOSE(fdP);
2660     /*
2661      * Set up and return modified status for the parent dir and new symlink
2662      * to caller.
2663      */
2664     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2665     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
2666
2667     /* convert the write lock to a read lock before breaking callbacks */
2668     VVnodeWriteToRead(&errorCode, parentptr);
2669     assert(!errorCode || errorCode == VSALVAGE);
2670
2671     /* break call back on the parent dir */
2672     BreakCallBack(client->host, DirFid, 0);
2673
2674 Bad_SymLink: 
2675     /* Write the all modified vnodes (parent, new files) and volume back */
2676     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2677     ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode));
2678     return errorCode;
2679
2680 } /*SAFSS_Symlink*/
2681
2682
2683 SRXAFS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid, OutFidStatus, OutDirStatus, Sync)
2684     struct AFSVolSync *Sync;
2685     struct rx_connection *tcon;          /* Rx connection handle */
2686     struct AFSFid *DirFid;               /* Parent dir's fid */
2687     char *Name;                          /* File name to create */
2688     char *LinkContents;                  /* Contents of the new created file */
2689     struct AFSStoreStatus *InStatus;     /* Input status for the new symbolic link */
2690     struct AFSFid *OutFid;               /* Fid for newly created symbolic link */
2691     struct AFSFetchStatus *OutFidStatus; /* Output status for new symbolic link */
2692     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2693
2694 {
2695     afs_int32 code;
2696     struct rx_call *tcall = (struct rx_call *) tcon; 
2697 #if FS_STATS_DETAILED
2698     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2699     struct timeval opStartTime,
2700                    opStopTime;              /* Start/stop times for RPC op*/
2701     struct timeval elapsedTime;             /* Transfer time */
2702
2703     /*
2704      * Set our stats pointer, remember when the RPC operation started, and
2705      * tally the operation.
2706      */
2707     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SYMLINK]);
2708     FS_LOCK
2709     (opP->numOps)++;
2710     FS_UNLOCK
2711     TM_GetTimeOfDay(&opStartTime, 0);
2712 #endif /* FS_STATS_DETAILED */
2713
2714     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2715         goto Bad_Symlink;
2716
2717     code = SAFSS_Symlink (tcon, DirFid, Name, LinkContents, InStatus, OutFid,
2718                          OutFidStatus, OutDirStatus, Sync);
2719
2720 Bad_Symlink:    
2721     CallPostamble(tcon);
2722
2723 #if FS_STATS_DETAILED
2724     TM_GetTimeOfDay(&opStopTime, 0);
2725     if (code == 0) {
2726       FS_LOCK
2727       (opP->numSuccesses)++;
2728       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2729       fs_stats_AddTo((opP->sumTime), elapsedTime);
2730       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2731       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2732         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2733       }
2734       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2735         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2736       }
2737       FS_UNLOCK
2738     }
2739
2740 #endif /* FS_STATS_DETAILED */
2741
2742     osi_auditU (tcall, SymlinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
2743     return code;
2744
2745 } /*SRXAFS_Symlink*/
2746
2747
2748 /*
2749  * This routine is called exclusively by SRXAFS_Link(), and should be
2750  * merged into it when possible.
2751  */
2752 SAFSS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2753     struct rx_connection *tcon;          /* Rx connection handle */
2754     struct AFSFid *DirFid;               /* Parent dir's fid */
2755     char *Name;                          /* File name to create */
2756     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2757     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2758     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2759     struct AFSVolSync *Sync;
2760
2761 {
2762     Vnode * parentptr = 0;              /* vnode of input Directory */
2763     Vnode * targetptr = 0;              /* vnode of the new file */
2764     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2765     Volume * volptr = 0;                /* pointer to the volume header */
2766     int     errorCode = 0;              /* error code */
2767     DirHandle dir;                      /* Handle for dir package I/O */
2768     struct client * client;             /* pointer to client structure */
2769     afs_int32 rights, anyrights;                /* rights for this and any user */
2770     struct client *t_client;            /* tmp ptr to client data */
2771     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2772
2773     /* Get ptr to client data for user Id for logging */
2774     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2775     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2776     ViceLog(1, ("SAFS_Link %s,  Did = %u.%d.%d, Fid = %u.%d.%d, Host %s, Id %d\n",
2777             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2778             ExistingFid->Volume, ExistingFid->Vnode, ExistingFid->Unique,
2779             inet_ntoa(logHostAddr), t_client->ViceId));
2780     FS_LOCK
2781     AFSCallStats.Link++, AFSCallStats.TotalCalls++;
2782     FS_UNLOCK
2783     if (DirFid->Volume != ExistingFid->Volume) {
2784         errorCode = EXDEV;
2785         goto Bad_Link;
2786     }
2787     if (!FileNameOK(Name)) {
2788         errorCode = EINVAL;
2789         goto Bad_Link;
2790     }
2791
2792     /*
2793      * Get the vnode and volume for the parent dir along with the caller's
2794      * rights to it
2795      */
2796     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2797                                      MustBeDIR, &parentwhentargetnotdir,
2798                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2799         goto Bad_Link;
2800     }
2801
2802     /* set volume synchronization information */
2803     SetVolumeSync(Sync, volptr);
2804
2805     /* Can the caller insert into the parent directory? */
2806     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
2807         goto Bad_Link;
2808     }
2809
2810     if (((DirFid->Vnode & 1) && (ExistingFid->Vnode & 1)) ||
2811         (DirFid->Vnode == ExistingFid->Vnode)) {  /* at present, */
2812       /* AFS fileservers always have directory vnodes that are odd.   */
2813       errorCode = EISDIR;
2814       goto Bad_Link;
2815     }
2816
2817     /* get the file vnode  */
2818     if (errorCode = CheckVnode(ExistingFid, &volptr, &targetptr, WRITE_LOCK)) {
2819         goto Bad_Link;
2820     }
2821     if (targetptr->disk.type != vFile) {
2822         errorCode = EISDIR;
2823         goto Bad_Link;
2824     }
2825     if (targetptr->disk.parent != DirFid->Vnode) {
2826         errorCode = EXDEV;
2827         goto Bad_Link;
2828     }
2829     if (parentptr->disk.cloned) 
2830     {
2831         ViceLog(25, ("Link : calling CopyOnWrite on  target dir\n"));
2832         if ( errorCode = CopyOnWrite(parentptr, volptr))
2833                 goto Bad_Link;          /* disk full error */
2834     }
2835
2836     /* add the name to the directory */
2837     SetDirHandle(&dir, parentptr);
2838     if (errorCode = Create(&dir, (char *)Name, ExistingFid))
2839         goto Bad_Link;
2840     DFlush();
2841
2842     /* update the status in the parent vnode */
2843     /**WARNING** --> disk.author SHOULDN'T be modified???? */
2844 #if FS_STATS_DETAILED
2845     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2846                              parentptr->disk.linkCount, client->InSameNetwork);
2847 #else
2848     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
2849                              parentptr->disk.linkCount);
2850 #endif /* FS_STATS_DETAILED */
2851
2852     targetptr->disk.linkCount++;
2853     targetptr->disk.author = client->ViceId;
2854     targetptr->changed_newTime = 1; /* Status change of linked-to file */
2855
2856     /* set up return status */
2857     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
2858     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct vnode *)0);
2859
2860     /* convert the write locks to read locks before breaking callbacks */
2861     VVnodeWriteToRead(&errorCode, targetptr);
2862     assert(!errorCode || errorCode == VSALVAGE);
2863     VVnodeWriteToRead(&errorCode, parentptr);
2864     assert(!errorCode || errorCode == VSALVAGE);
2865     
2866     /* break call back on DirFid */
2867     BreakCallBack(client->host, DirFid, 0);
2868     /*
2869      * We also need to break the callback for the file that is hard-linked since part 
2870      * of its status (like linkcount) is changed
2871      */
2872     BreakCallBack(client->host, ExistingFid, 0);
2873
2874 Bad_Link:
2875     /* Write the all modified vnodes (parent, new files) and volume back */
2876     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
2877     ViceLog(2, ("SAFS_Link returns %d\n", errorCode));
2878     return errorCode;
2879
2880 } /*SAFSS_Link*/
2881
2882
2883 SRXAFS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus, OutDirStatus, Sync)
2884     struct AFSVolSync *Sync;
2885     struct rx_connection *tcon;          /* Rx connection handle */
2886     struct AFSFid *DirFid;               /* Parent dir's fid */
2887     char *Name;                          /* File name to create */
2888     struct AFSFid *ExistingFid;          /* Fid of existing fid we'll make link to */
2889     struct AFSFetchStatus *OutFidStatus; /* Output status for newly created file */
2890     struct AFSFetchStatus *OutDirStatus; /* Outpout status for parent dir */
2891
2892 {
2893     afs_int32 code;
2894     struct rx_call *tcall = (struct rx_call *) tcon; 
2895 #if FS_STATS_DETAILED
2896     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
2897     struct timeval opStartTime,
2898                    opStopTime;              /* Start/stop times for RPC op*/
2899     struct timeval elapsedTime;             /* Transfer time */
2900
2901     /*
2902      * Set our stats pointer, remember when the RPC operation started, and
2903      * tally the operation.
2904      */
2905     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_LINK]);
2906     FS_LOCK
2907     (opP->numOps)++;
2908     FS_UNLOCK
2909     TM_GetTimeOfDay(&opStartTime, 0);
2910 #endif /* FS_STATS_DETAILED */
2911
2912     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
2913         goto Bad_Link;
2914
2915     code = SAFSS_Link (tcon, DirFid, Name, ExistingFid, OutFidStatus,
2916                       OutDirStatus, Sync);
2917     
2918 Bad_Link:
2919     CallPostamble(tcon);
2920
2921 #if FS_STATS_DETAILED
2922     TM_GetTimeOfDay(&opStopTime, 0);
2923     if (code == 0) {
2924       FS_LOCK
2925       (opP->numSuccesses)++;
2926       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
2927       fs_stats_AddTo((opP->sumTime), elapsedTime);
2928       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
2929       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
2930         fs_stats_TimeAssign((opP->minTime), elapsedTime);
2931       }
2932       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
2933         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
2934       }
2935       FS_UNLOCK
2936     }
2937
2938 #endif /* FS_STATS_DETAILED */
2939
2940     osi_auditU (tcall, LinkEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_FID, ExistingFid, AUD_END);
2941     return code;
2942
2943 } /*SRXAFS_Link*/
2944
2945
2946 /*
2947  * This routine is called exclusively by SRXAFS_MakeDir(), and should be
2948  * merged into it when possible.
2949  */
2950 SAFSS_MakeDir (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus,
2951               OutDirStatus, CallBack, Sync)
2952     struct rx_connection *tcon;          /* Rx connection handle */
2953     struct AFSFid *DirFid;               /* Parent dir's fid */
2954     char *Name;                          /* Name of dir to be created */
2955     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
2956     struct AFSFid *OutFid;               /* Fid of new dir */
2957     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
2958     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
2959     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
2960     struct AFSVolSync *Sync;
2961
2962 {
2963     Vnode * parentptr = 0;              /* vnode of input Directory */
2964     Vnode * targetptr = 0;              /* vnode of the new file */
2965     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
2966     Volume * volptr = 0;                /* pointer to the volume header */
2967     int     errorCode = 0;              /* error code */
2968     struct acl_accessList * newACL;     /* Access list */
2969     int     newACLSize;                 /* Size of access list */
2970     DirHandle dir;                      /* Handle for dir package I/O */
2971     DirHandle parentdir;                /* Handle for dir package I/O */
2972     struct client * client;             /* pointer to client structure */
2973     afs_int32 rights, anyrights;                /* rights for this and any user */
2974     struct client *t_client;            /* tmp ptr to client data */
2975     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
2976
2977     /* Get ptr to client data for user Id for logging */
2978     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
2979     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
2980     ViceLog(1, ("SAFS_MakeDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
2981             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
2982             inet_ntoa(logHostAddr), t_client->ViceId));
2983     FS_LOCK
2984     AFSCallStats.MakeDir++, AFSCallStats.TotalCalls++;    
2985     FS_UNLOCK
2986     if (!FileNameOK(Name)) {
2987         errorCode = EINVAL;
2988         goto Bad_MakeDir;
2989     }
2990
2991     /*
2992      * Get the vnode and volume for the parent dir along with the caller's
2993      * rights to it.
2994      */
2995     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
2996                                      MustBeDIR, &parentwhentargetnotdir,
2997                                      &client, WRITE_LOCK, &rights, &anyrights)) {
2998         goto Bad_MakeDir;
2999     }
3000  
3001     /* set volume synchronization information */
3002     SetVolumeSync(Sync, volptr);
3003
3004     /* Write access to the parent directory? */
3005 #ifdef DIRCREATE_NEED_WRITE
3006     /*
3007      * requires w access for the user to create a directory. this
3008      * closes a loophole in the current security arrangement, since a
3009      * user with i access only can create a directory and get the
3010      * implcit a access that goes with dir ownership, and proceed to 
3011      * subvert quota in the volume.
3012      */
3013     if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) ||
3014         (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
3015 #else 
3016     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)) {
3017 #endif /* DIRCREATE_NEED_WRITE */ 
3018         goto Bad_MakeDir;
3019     }
3020
3021 #define EMPTYDIRBLOCKS 2
3022     /* get a new vnode and set it up */
3023     if (errorCode = Alloc_NewVnode(parentptr, &parentdir, volptr, &targetptr,
3024                                    Name, OutFid, vDirectory, EMPTYDIRBLOCKS)) {
3025         goto Bad_MakeDir;
3026     }
3027
3028     /* Update the status for the parent dir */
3029 #if FS_STATS_DETAILED
3030     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
3031                              parentptr->disk.linkCount+1, client->InSameNetwork);
3032 #else
3033     Update_ParentVnodeStatus(parentptr, volptr, &parentdir, client->ViceId,
3034                              parentptr->disk.linkCount+1);
3035 #endif /* FS_STATS_DETAILED */
3036
3037     /* Point to target's ACL buffer and copy the parent's ACL contents to it */
3038     assert((SetAccessList(&targetptr, &volptr, &newACL, &newACLSize,
3039                           &parentwhentargetnotdir, (AFSFid *)0, 0)) == 0);
3040     assert(parentwhentargetnotdir == 0);
3041     memcpy((char *)newACL, (char *)VVnodeACL(parentptr), VAclSize(parentptr));
3042
3043     /* update the status for the target vnode */
3044     Update_TargetVnodeStatus(targetptr, TVS_MKDIR, client, InStatus,
3045                              parentptr, volptr, 0);
3046
3047     /* Actually create the New directory in the directory package */
3048     SetDirHandle(&dir, targetptr);
3049     assert(!(MakeDir(&dir, OutFid, DirFid)));
3050     DFlush();
3051     targetptr->disk.length = Length(&dir);
3052
3053     /* set up return status */
3054     GetStatus(targetptr, OutFidStatus, rights, anyrights, parentptr);
3055     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
3056
3057     /* convert the write lock to a read lock before breaking callbacks */
3058     VVnodeWriteToRead(&errorCode, parentptr);
3059     assert(!errorCode || errorCode == VSALVAGE);
3060
3061     /* break call back on DirFid */
3062     BreakCallBack(client->host, DirFid, 0);
3063
3064     /* Return a callback promise to caller */
3065     SetCallBackStruct(AddCallBack(client->host, OutFid), CallBack);
3066
3067 Bad_MakeDir: 
3068     /* Write the all modified vnodes (parent, new files) and volume back */
3069     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3070     ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); 
3071     return errorCode;
3072
3073 } /*SAFSS_MakeDir*/
3074
3075
3076 SRXAFS_MakeDir (tcon, DirFid, Name, InStatus, OutFid, OutFidStatus, OutDirStatus, CallBack, Sync)
3077     struct AFSVolSync *Sync;
3078     struct rx_connection *tcon;          /* Rx connection handle */
3079     struct AFSFid *DirFid;               /* Parent dir's fid */
3080     char *Name;                          /* Name of dir to be created */
3081     struct AFSStoreStatus *InStatus;     /* Input status for new dir */
3082     struct AFSFid *OutFid;               /* Fid of new dir */
3083     struct AFSFetchStatus *OutFidStatus; /* Output status for new directory */
3084     struct AFSFetchStatus *OutDirStatus; /* Output status for parent dir */
3085     struct AFSCallBack *CallBack;        /* Returned callback promise for new dir */
3086
3087 {
3088     afs_int32 code;
3089     struct rx_call *tcall = (struct rx_call *) tcon; 
3090 #if FS_STATS_DETAILED
3091     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3092     struct timeval opStartTime,
3093                    opStopTime;              /* Start/stop times for RPC op*/
3094     struct timeval elapsedTime;             /* Transfer time */
3095
3096     /*
3097      * Set our stats pointer, remember when the RPC operation started, and
3098      * tally the operation.
3099      */
3100     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_MAKEDIR]);
3101     FS_LOCK
3102     (opP->numOps)++;
3103     FS_UNLOCK
3104     TM_GetTimeOfDay(&opStartTime, 0);
3105 #endif /* FS_STATS_DETAILED */
3106     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3107         goto Bad_MakeDir;
3108
3109     code = SAFSS_MakeDir (tcon, DirFid, Name, InStatus, OutFid,
3110                          OutFidStatus, OutDirStatus, CallBack, Sync);
3111     
3112 Bad_MakeDir:
3113     CallPostamble(tcon);
3114
3115 #if FS_STATS_DETAILED
3116     TM_GetTimeOfDay(&opStopTime, 0);
3117     if (code == 0) {
3118       FS_LOCK
3119       (opP->numSuccesses)++;
3120       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3121       fs_stats_AddTo((opP->sumTime), elapsedTime);
3122       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3123       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3124         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3125       }
3126       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3127         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3128       }
3129       FS_UNLOCK
3130     }
3131
3132 #endif /* FS_STATS_DETAILED */
3133
3134     osi_auditU (tcall, MakeDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3135     return code;
3136
3137 } /*SRXAFS_MakeDir*/
3138
3139
3140 /*
3141  * This routine is called exclusively by SRXAFS_RemoveDir(), and should be
3142  * merged into it when possible.
3143  */
3144 SAFSS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync)
3145     struct rx_connection *tcon;          /* Rx connection handle */
3146     struct AFSFid *DirFid;               /* Parent dir's fid */
3147     char *Name;                          /* (Empty) dir's name to be removed */
3148     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3149     struct AFSVolSync *Sync;
3150
3151 {
3152     Vnode * parentptr = 0;              /* vnode of input Directory */
3153     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3154     Vnode * targetptr = 0;              /* file to be deleted */
3155     AFSFid fileFid;                     /* area for Fid from the directory */
3156     int     errorCode = 0;              /* error code */
3157     DirHandle dir;                      /* Handle for dir package I/O */
3158     Volume * volptr = 0;                /* pointer to the volume header */
3159     struct client * client;             /* pointer to client structure */
3160     afs_int32 rights, anyrights;                /* rights for this and any user */
3161     Vnode debugvnode1, debugvnode2;
3162     struct client *t_client;            /* tmp ptr to client data */
3163     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3164
3165     /* Get ptr to client data for user Id for logging */
3166     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3167     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3168     ViceLog(1, ("SAFS_RemoveDir %s,  Did = %u.%d.%d, Host %s, Id %d\n",
3169             Name, DirFid->Volume, DirFid->Vnode, DirFid->Unique,
3170             inet_ntoa(logHostAddr), t_client->ViceId));
3171     FS_LOCK
3172     AFSCallStats.RemoveDir++, AFSCallStats.TotalCalls++;
3173     FS_UNLOCK
3174     /*
3175      * Get the vnode and volume for the parent dir along with the caller's
3176      * rights to it
3177      */
3178     if (errorCode = GetVolumePackage(tcon, DirFid, &volptr, &parentptr,
3179                                      MustBeDIR, &parentwhentargetnotdir,
3180                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3181         goto Bad_RemoveDir;
3182     }
3183     debugvnode1 = *parentptr;
3184
3185     /* set volume synchronization information */
3186     SetVolumeSync(Sync, volptr);
3187
3188     /* Does the caller has delete (&write) access to the parent dir? */
3189     if (errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE)) {
3190         goto Bad_RemoveDir;
3191     }
3192
3193     debugvnode2 = *parentptr;
3194     /* Do the actual delete of the desired (empty) directory, Name */
3195     if (errorCode = DeleteTarget(parentptr, volptr, &targetptr, &dir, &fileFid,
3196                                  Name, MustBeDIR)) {
3197         goto Bad_RemoveDir;
3198     }
3199
3200     /* Update the status for the parent dir; link count is also adjusted */
3201 #if FS_STATS_DETAILED
3202     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3203                              parentptr->disk.linkCount-1, client->InSameNetwork);
3204 #else
3205     Update_ParentVnodeStatus(parentptr, volptr, &dir, client->ViceId,
3206                              parentptr->disk.linkCount-1);
3207 #endif /* FS_STATS_DETAILED */
3208
3209     /* Return to the caller the updated parent dir status */
3210     GetStatus(parentptr, OutDirStatus, rights, anyrights, (struct Vnode *)0);
3211
3212     /*
3213      * Note: it is not necessary to break the callback on fileFid, since
3214      * refcount is now 0, so no one should be able to refer to the dir
3215      * any longer
3216      */
3217     DeleteFileCallBacks(&fileFid);
3218
3219     /* convert the write lock to a read lock before breaking callbacks */
3220     VVnodeWriteToRead(&errorCode, parentptr);
3221     assert(!errorCode || errorCode == VSALVAGE);
3222
3223     /* break call back on DirFid and fileFid */
3224     BreakCallBack(client->host, DirFid, 0);
3225
3226 Bad_RemoveDir: 
3227     /* Write the all modified vnodes (parent, new files) and volume back */
3228     PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr);
3229     ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode));
3230     return errorCode;
3231
3232 } /*SAFSS_RemoveDir*/
3233
3234
3235 SRXAFS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync)
3236     struct AFSVolSync *Sync;
3237     struct rx_connection *tcon;          /* Rx connection handle */
3238     struct AFSFid *DirFid;               /* Parent dir's fid */
3239     char *Name;                          /* (Empty) dir's name to be removed */
3240     struct AFSFetchStatus *OutDirStatus; /* Output status for the parent dir */
3241
3242 {
3243     afs_int32 code;
3244     struct rx_call *tcall = (struct rx_call *) tcon; 
3245 #if FS_STATS_DETAILED
3246     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3247     struct timeval opStartTime,
3248                    opStopTime;              /* Start/stop times for RPC op*/
3249     struct timeval elapsedTime;             /* Transfer time */
3250
3251     /*
3252      * Set our stats pointer, remember when the RPC operation started, and
3253      * tally the operation.
3254      */
3255     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_REMOVEDIR]);
3256     FS_LOCK
3257     (opP->numOps)++;
3258     FS_UNLOCK
3259     TM_GetTimeOfDay(&opStartTime, 0);
3260 #endif /* FS_STATS_DETAILED */
3261
3262     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3263         goto Bad_RemoveDir;
3264
3265     code = SAFSS_RemoveDir (tcon, DirFid, Name, OutDirStatus, Sync);
3266     
3267 Bad_RemoveDir:
3268     CallPostamble(tcon);
3269
3270 #if FS_STATS_DETAILED
3271     TM_GetTimeOfDay(&opStopTime, 0);
3272     if (code == 0) {
3273       FS_LOCK
3274       (opP->numSuccesses)++;
3275       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3276       fs_stats_AddTo((opP->sumTime), elapsedTime);
3277       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3278       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3279         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3280       }
3281       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3282         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3283       }
3284       FS_UNLOCK
3285     }
3286
3287 #endif /* FS_STATS_DETAILED */
3288
3289     osi_auditU (tcall, RemoveDirEvent, code, AUD_FID, DirFid, AUD_STR, Name, AUD_END);
3290     return code;
3291
3292 } /*SRXAFS_RemoveDir*/
3293
3294
3295 /*
3296  * This routine is called exclusively by SRXAFS_SetLock(), and should be
3297  * merged into it when possible.
3298  */
3299 SAFSS_SetLock (tcon, Fid, type, Sync)
3300     struct rx_connection *tcon; /* Rx connection handle */
3301     struct AFSFid *Fid;         /* Fid of file to lock */
3302     ViceLockType type;          /* Type of lock (Read or write) */
3303     struct AFSVolSync *Sync;
3304
3305 {
3306     Vnode * targetptr = 0;              /* vnode of input file */
3307     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3308     int     errorCode = 0;              /* error code */
3309     Volume * volptr = 0;                /* pointer to the volume header */
3310     struct client * client;             /* pointer to client structure */
3311     afs_int32 rights, anyrights;                /* rights for this and any user */
3312     struct client *t_client;            /* tmp ptr to client data */
3313     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3314     static char * locktype[2] = {"LockRead","LockWrite"};
3315
3316     if (type != LockRead && type != LockWrite) {
3317         errorCode = EINVAL;
3318         goto Bad_SetLock;
3319     }
3320     /* Get ptr to client data for user Id for logging */
3321     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3322     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3323     ViceLog(1,("SAFS_SetLock type = %s Fid = %u.%d.%d, Host %s, Id %d\n",
3324             locktype[(int)type], Fid->Volume, Fid->Vnode, Fid->Unique,
3325             inet_ntoa(logHostAddr), t_client->ViceId));
3326     FS_LOCK
3327     AFSCallStats.SetLock++, AFSCallStats.TotalCalls++;
3328     FS_UNLOCK
3329
3330     /*
3331      * Get the vnode and volume for the desired file along with the caller's
3332      * rights to it
3333      */
3334     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3335                                      DONTCHECK, &parentwhentargetnotdir,
3336                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3337         goto Bad_SetLock;
3338     }
3339
3340     /* set volume synchronization information */
3341     SetVolumeSync(Sync, volptr);
3342
3343     /* Handle the particular type of set locking, type */
3344     errorCode = HandleLocking(targetptr, rights, type);
3345
3346 Bad_SetLock: 
3347     /* Write the all modified vnodes (parent, new files) and volume back */
3348     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3349
3350     if ((errorCode == VREADONLY) && (type == LockRead))
3351        errorCode = 0;  /* allow read locks on RO volumes without saving state */
3352
3353     ViceLog(2,("SAFS_SetLock returns %d\n", errorCode));
3354     return(errorCode);
3355
3356 }  /*SAFSS_SetLock*/
3357
3358
3359 SRXAFS_OldSetLock(tcon, Fid, type, Sync)
3360     struct AFSVolSync *Sync;
3361     struct rx_connection *tcon; /* Rx connection handle */
3362     struct AFSFid *Fid;         /* Fid of file to lock */
3363     ViceLockType type;          /* Type of lock (Read or write) */
3364
3365 {
3366     return SRXAFS_SetLock(tcon, Fid, type, Sync);
3367
3368 } /*SRXAFS_OldSetLock*/
3369
3370
3371 SRXAFS_SetLock (tcon, Fid, type, Sync)
3372     struct AFSVolSync *Sync;
3373     struct rx_connection *tcon; /* Rx connection handle */
3374     struct AFSFid *Fid;         /* Fid of file to lock */
3375     ViceLockType type;          /* Type of lock (Read or write) */
3376
3377 {
3378     afs_int32 code;
3379     struct rx_call *tcall = (struct rx_call *) tcon; 
3380 #if FS_STATS_DETAILED
3381     struct fs_stats_opTimingData *opP;      /* Ptr to this op's timing struct */
3382     struct timeval opStartTime,
3383                    opStopTime;              /* Start/stop times for RPC op*/
3384     struct timeval elapsedTime;             /* Transfer time */
3385
3386     /*
3387      * Set our stats pointer, remember when the RPC operation started, and
3388      * tally the operation.
3389      */
3390     opP = &(afs_FullPerfStats.det.rpcOpTimes[FS_STATS_RPCIDX_SETLOCK]);
3391     FS_LOCK
3392     (opP->numOps)++;
3393     FS_UNLOCK
3394     TM_GetTimeOfDay(&opStartTime, 0);
3395 #endif /* FS_STATS_DETAILED */
3396
3397     if (code = CallPreamble((struct rx_call **) &tcon, ACTIVECALL))
3398         goto Bad_SetLock;
3399
3400     code = SAFSS_SetLock (tcon, Fid, type, Sync);
3401     
3402 Bad_SetLock:
3403     CallPostamble(tcon);
3404
3405 #if FS_STATS_DETAILED
3406     TM_GetTimeOfDay(&opStopTime, 0); 
3407     if (code == 0) {
3408       FS_LOCK
3409       (opP->numSuccesses)++;
3410       fs_stats_GetDiff(elapsedTime, opStartTime, opStopTime);
3411       fs_stats_AddTo((opP->sumTime), elapsedTime);
3412       fs_stats_SquareAddTo((opP->sqrTime), elapsedTime);
3413       if (fs_stats_TimeLessThan(elapsedTime, (opP->minTime))) {
3414         fs_stats_TimeAssign((opP->minTime), elapsedTime);
3415       }
3416       if (fs_stats_TimeGreaterThan(elapsedTime, (opP->maxTime))) {
3417         fs_stats_TimeAssign((opP->maxTime), elapsedTime);
3418       }
3419       FS_UNLOCK
3420     }
3421 #endif /* FS_STATS_DETAILED */
3422
3423     osi_auditU (tcall, SetLockEvent, code, AUD_FID, Fid, AUD_LONG, type, AUD_END);
3424     return code;
3425
3426 } /*SRXAFS_SetLock*/
3427
3428
3429 /*
3430  * This routine is called exclusively by SRXAFS_ExtendLock(), and should be
3431  * merged into it when possible.
3432  */
3433 SAFSS_ExtendLock (tcon, Fid, Sync)
3434     struct rx_connection *tcon; /* Rx connection handle */
3435     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3436     struct AFSVolSync *Sync;
3437
3438 {
3439     Vnode * targetptr = 0;              /* vnode of input file */
3440     Vnode * parentwhentargetnotdir = 0; /* parent for use in SetAccessList */
3441     int     errorCode = 0;              /* error code */
3442     Volume * volptr = 0;                /* pointer to the volume header */
3443     struct client * client;             /* pointer to client structure */
3444     afs_int32 rights, anyrights;                /* rights for this and any user */
3445     struct client *t_client;            /* tmp ptr to client data */
3446     struct in_addr logHostAddr;         /* host ip holder for inet_ntoa */
3447
3448     /* Get ptr to client data for user Id for logging */
3449     t_client = (struct client *) rx_GetSpecific(tcon, rxcon_client_key); 
3450     logHostAddr.s_addr =  rx_HostOf(rx_PeerOf(tcon));
3451     ViceLog(1,("SAFS_ExtendLock Fid = %u.%d.%d, Host %s, Id %d\n", 
3452                Fid->Volume, Fid->Vnode, Fid->Unique, 
3453                inet_ntoa(logHostAddr), t_client->ViceId));
3454     FS_LOCK
3455     AFSCallStats.ExtendLock++, AFSCallStats.TotalCalls++;    
3456     FS_UNLOCK
3457     /*
3458      * Get the vnode and volume for the desired file along with the caller's
3459      * rights to it
3460      */
3461     if (errorCode = GetVolumePackage(tcon, Fid, &volptr, &targetptr,
3462                                      DONTCHECK, &parentwhentargetnotdir,
3463                                      &client, WRITE_LOCK, &rights, &anyrights)) {
3464         goto Bad_ExtendLock;
3465     }
3466
3467     /* set volume synchronization information */
3468     SetVolumeSync(Sync, volptr);
3469
3470     /* Handle the actual lock extension */
3471     errorCode = HandleLocking(targetptr, rights, LockExtend);
3472
3473 Bad_ExtendLock: 
3474     /* Put back file's vnode and volume */
3475     PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *)0, volptr);
3476
3477     if ((errorCode == VREADONLY))  /* presumably, we already granted this lock */
3478        errorCode = 0;              /* under our generous policy re RO vols */
3479
3480     ViceLog(2,("SAFS_ExtendLock returns %d\n", errorCode));
3481     return(errorCode);
3482
3483 } /*SAFSS_ExtendLock*/
3484
3485
3486 SRXAFS_OldExtendLock (tcon, Fid, Sync)
3487     struct AFSVolSync *Sync;
3488     struct rx_connection *tcon; /* Rx connection handle */
3489     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3490
3491 {
3492     return SRXAFS_ExtendLock(tcon, Fid, Sync);
3493
3494 } /*SRXAFS_OldExtendLock*/
3495
3496
3497 SRXAFS_ExtendLock (tcon, Fid, Sync)
3498     struct AFSVolSync *Sync;
3499     struct rx_connection *tcon; /* Rx connection handle */
3500     struct AFSFid *Fid;         /* Fid of file whose lock we extend */
3501
3502 {
3503     afs_int32 code;