openbsd-flock-fix-20030707
[openafs.git] / src / afs / VNOPS / afs_vnop_open.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 /*
11  * Implements:
12  * afs_open
13  *
14  */
15
16
17 #include <afsconfig.h>
18 #include "afs/param.h"
19
20 RCSID("$Header$");
21
22 #include "afs/sysincludes.h"    /* Standard vendor system headers */
23 #include "afsincludes.h"        /* Afs-based standard headers */
24 #include "afs/afs_stats.h" /* statistics */
25 #include "afs/afs_cbqueue.h"
26 #include "afs/nfsclient.h"
27 #include "afs/afs_osidnlc.h"
28
29
30
31 /* given a vnode ptr, open flags and credentials, open the file.  No access
32  * checks are done here, instead they're done by afs_create or afs_access,
33  * both called by the vn_open call.
34  */
35 int
36 #ifdef AFS_SGI64_ENV
37 afs_open(bhv_desc_t *bhv, struct vcache **avcp, afs_int32 aflags, struct AFS_UCRED *acred)
38 #else
39 afs_open(struct vcache **avcp, afs_int32 aflags, struct AFS_UCRED *acred)
40 #endif
41 {
42     register afs_int32 code;
43     struct vrequest treq;
44     struct vcache *tvc;
45     int writing;
46     struct afs_fakestat_state fakestate;
47     
48     AFS_STATCNT(afs_open);
49     if ((code = afs_InitReq(&treq, acred))) return code;
50 #ifdef AFS_SGI64_ENV
51     /* avcpp can be, but is not necesarily, bhp's vnode. */
52     tvc = VTOAFS(BHV_TO_VNODE(bhv));
53 #else
54     tvc = *avcp;
55 #endif
56     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
57                ICL_TYPE_INT32, aflags);
58     afs_InitFakeStat(&fakestate);
59     code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
60     if (code) goto done;
61     code = afs_VerifyVCache(tvc, &treq);
62     if (code) goto done;
63     if (aflags & (FWRITE | FTRUNC)) writing = 1;
64     else writing = 0;
65     if (vType(tvc) == VDIR) {
66         /* directory */
67         if (writing) {
68             code = EISDIR;
69             goto done;
70         }
71         else {
72             if (!afs_AccessOK(tvc, 
73                         ((tvc->states & CForeign) ? PRSFS_READ: PRSFS_LOOKUP),
74                         &treq, CHECK_MODE_BITS)) {
75                 code = EACCES;
76                 goto done;
77             }
78         }
79     }
80     else {
81 #ifdef  AFS_SUN5_ENV
82         if (AFS_NFSXLATORREQ(acred) &&  (aflags & FREAD)) {
83             if (!afs_AccessOK(tvc, PRSFS_READ, &treq,
84                               CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
85                 code = EACCES;
86                 goto done;
87             }
88         }
89 #endif
90 #ifdef  AFS_AIX41_ENV
91         if (aflags & FRSHARE) {
92             /*
93              * Hack for AIX 4.1:
94              *  Apparently it is possible for a file to get mapped without
95              *  either VNOP_MAP or VNOP_RDWR being called, if (1) it is a
96              *  sharable library, and (2) it has already been loaded.  We must
97              *  ensure that the credp is up to date.  We detect the situation
98              *  by checking for O_RSHARE at open time.
99              */
100             /*
101              * We keep the caller's credentials since an async daemon will
102              * handle the request at some point. We assume that the same
103              * credentials will be used.
104              */
105             ObtainWriteLock(&tvc->lock,140);
106             if (!tvc->credp || (tvc->credp != acred)) {
107                 crhold(acred);
108                 if (tvc->credp) {
109                     struct ucred *crp = tvc->credp;
110                     tvc->credp = NULL;
111                     crfree(crp);
112                 }
113                 tvc->credp = acred;
114             }
115             ReleaseWriteLock(&tvc->lock);
116         }
117 #endif
118         /* normal file or symlink */
119         osi_FlushText(tvc); /* only needed to flush text if text locked last time */
120 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
121         afs_BozonLock(&tvc->pvnLock, tvc);
122 #endif
123         osi_FlushPages(tvc, acred);
124 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
125         afs_BozonUnlock(&tvc->pvnLock, tvc);
126 #endif
127     }
128     /* set date on file if open in O_TRUNC mode */
129     if (aflags & FTRUNC) {
130         /* this fixes touch */
131         ObtainWriteLock(&tvc->lock,123);
132         tvc->m.Date = osi_Time();
133         tvc->states |= CDirty;
134         ReleaseWriteLock(&tvc->lock);
135     }
136     ObtainReadLock(&tvc->lock);
137     if (writing) tvc->execsOrWriters++;
138     tvc->opens++;
139 #if defined(AFS_SGI_ENV)
140     if (writing && tvc->cred == NULL) {
141         crhold(acred);
142         tvc->cred = acred;
143     }
144 #endif
145     ReleaseReadLock(&tvc->lock);
146 done:
147     afs_PutFakeStat(&fakestate);
148     code = afs_CheckCode(code, &treq, 4); /* avoid AIX -O bug */
149
150     afs_Trace2(afs_iclSetp, CM_TRACE_OPEN, ICL_TYPE_POINTER, tvc,
151                ICL_TYPE_INT32, 999999);
152
153     return code;
154 }