client-64bit-file-size-support-20011031
[openafs.git] / src / afs / VNOPS / afs_vnop_symlink.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  * afs_vnop_symlink.c - symlink and readlink vnodeops.
12  *
13  * Implements:
14  * afs_symlink
15  * afs_MemHandleLink
16  * afs_UFSHandleLink
17  * afs_readlink
18  *
19  */
20
21 #include <afsconfig.h>
22 #include "../afs/param.h"
23
24 RCSID("$Header$");
25
26 #include "../afs/sysincludes.h" /* Standard vendor system headers */
27 #include "../afs/afsincludes.h" /* Afs-based standard headers */
28 #include "../afs/afs_stats.h" /* statistics */
29 #include "../afs/afs_cbqueue.h"
30 #include "../afs/nfsclient.h"
31 #include "../afs/afs_osidnlc.h"
32
33 extern afs_rwlock_t afs_xvcache;
34 extern afs_rwlock_t afs_xcbhash;
35
36 /* Note: There is the bare bones beginning of symlink hints in the now
37  * defunct afs/afs_lookup.c file. Since they are not in use, making the call
38  * is just a performance hit.
39  */
40
41
42 /* don't set CDirty in here because RPC is called synchronously */
43 afs_symlink
44 #ifdef  AFS_OSF_ENV
45   (ndp, attrs, atargetName)
46     struct nameidata *ndp;
47     struct vattr *attrs;
48     register char *atargetName; {
49     register struct vcache *adp = (struct vcache *)ndp->ni_dvp;
50     char *aname = ndp->ni_dent.d_name;
51     struct ucred *acred = ndp->ni_cred;
52 #else   /* AFS_OSF_ENV */
53   (OSI_VC_ARG(adp), aname, attrs, atargetName, acred)
54     OSI_VC_DECL(adp);
55     char *atargetName;
56     char *aname;
57     struct vattr *attrs;
58     struct AFS_UCRED *acred; {
59 #endif
60     afs_uint32 now;
61     struct vrequest treq;
62     afs_int32 code;
63     struct conn *tc;
64     struct VenusFid newFid;
65     struct dcache *tdc;
66     afs_size_t offset, len;
67     afs_int32 alen;
68     struct server *hostp=0;
69     struct vcache *tvc;
70     struct AFSStoreStatus InStatus;
71     struct AFSFetchStatus OutFidStatus, OutDirStatus;
72     struct AFSCallBack CallBack;
73     struct AFSVolSync tsync;
74     struct volume*    volp=0;
75     XSTATS_DECLS
76     OSI_VC_CONVERT(adp)
77     
78     AFS_STATCNT(afs_symlink);
79     afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
80                 ICL_TYPE_STRING, aname);
81     if (code = afs_InitReq(&treq, acred))
82        return code;
83
84     code = afs_VerifyVCache(adp, &treq);
85     if (code) { 
86       code = afs_CheckCode(code, &treq, 30);
87       return code;
88     }
89
90     /** If the volume is read-only, return error without making an RPC to the
91       * fileserver
92       */
93     if ( adp->states & CRO ) {
94         code = EROFS;
95         return code;
96     }
97
98     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
99     InStatus.ClientModTime = osi_Time();
100     alen = strlen(atargetName);     /* we want it to include the null */
101     if (*atargetName == '#' || *atargetName == '%') {
102         InStatus.UnixModeBits = 0644;   /* mt pt: null from "." at end */
103         if (alen == 1) alen++;  /* Empty string */
104     } else {
105         InStatus.UnixModeBits = 0755;
106         alen++;     /* add in the null */
107     }
108     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
109     volp = afs_FindVolume(&adp->fid, READ_LOCK); /*parent is also in same vol*/
110     ObtainWriteLock(&adp->lock,156);
111     ObtainSharedLock(&afs_xvcache,17);  /* prevent others from creating this entry */
112     /* XXX Pay attention to afs_xvcache around the whole thing!! XXX */
113     do {
114         tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
115         if (tc) {
116             hostp = tc->srvr->server;
117             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SYMLINK);
118             if (adp->states & CForeign) {
119                 now = osi_Time();
120 #ifdef RX_ENABLE_LOCKS
121                 AFS_GUNLOCK();
122 #endif /* RX_ENABLE_LOCKS */
123                 code = RXAFS_DFSSymlink(tc->id, (struct AFSFid *) &adp->fid.Fid, aname,
124                                      atargetName, &InStatus, (struct AFSFid *) &newFid.Fid,
125                                      &OutFidStatus, &OutDirStatus, &CallBack, &tsync);
126 #ifdef RX_ENABLE_LOCKS
127                 AFS_GLOCK();
128 #endif /* RX_ENABLE_LOCKS */
129             } else {
130 #ifdef RX_ENABLE_LOCKS
131                 AFS_GUNLOCK();
132 #endif /* RX_ENABLE_LOCKS */
133                 code = RXAFS_Symlink(tc->id, (struct AFSFid *) &adp->fid.Fid, aname,
134                                      atargetName, &InStatus, (struct AFSFid *) &newFid.Fid,
135                                      &OutFidStatus, &OutDirStatus, &tsync);
136 #ifdef RX_ENABLE_LOCKS
137                 AFS_GLOCK();
138 #endif /* RX_ENABLE_LOCKS */
139             }
140           XSTATS_END_TIME;
141         }
142         else code = -1;
143     } while 
144        (afs_Analyze(tc, code, &adp->fid, &treq,
145                    AFS_STATS_FS_RPCIDX_SYMLINK, SHARED_LOCK, (struct cell *)0));
146
147     UpgradeSToWLock(&afs_xvcache,40);
148     if (code) {
149         if (code < 0) {
150           ObtainWriteLock(&afs_xcbhash, 499);
151           afs_DequeueCallback(adp);
152           adp->states &= ~CStatd;
153           ReleaseWriteLock(&afs_xcbhash);
154           osi_dnlc_purgedp(adp);
155         }
156         ReleaseWriteLock(&adp->lock);
157         ReleaseWriteLock(&afs_xvcache);
158         if (tdc) afs_PutDCache(tdc);
159         goto done;
160     }
161     /* otherwise, we should see if we can make the change to the dir locally */
162     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
163         /* we can do it locally */
164         code = afs_dir_Create(&tdc->f.inode, aname, &newFid.Fid);
165         if (code) { 
166             ZapDCE(tdc);        /* surprise error -- use invalid value */
167             DZap(&tdc->f.inode);
168         }
169     }
170     if (tdc) {
171         afs_PutDCache(tdc);
172     }
173     newFid.Cell = adp->fid.Cell;
174     newFid.Fid.Volume = adp->fid.Fid.Volume;
175     ReleaseWriteLock(&adp->lock);
176
177     /* now we're done with parent dir, create the link's entry.  Note that
178      * no one can get a pointer to the new cache entry until we release 
179      * the xvcache lock. */
180     tvc = afs_NewVCache(&newFid, hostp, 1, WRITE_LOCK);
181     ObtainWriteLock(&tvc->lock,157);
182     ObtainWriteLock(&afs_xcbhash, 500);
183     tvc->states |= CStatd;              /* have valid info */
184     tvc->states &= ~CBulkFetching;
185
186     if (adp->states & CForeign) {
187         tvc->states |= CForeign;
188         /* We don't have to worry about losing the callback since we're doing it 
189          * under the afs_xvcache lock actually, afs_NewVCache may drop the 
190          * afs_xvcache lock, if it calls afs_FlushVCache */
191         tvc->cbExpires = CallBack.ExpirationTime + now;
192         afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
193     } else {
194         tvc->cbExpires = 0x7fffffff;    /* never expires, they can't change */
195      /* since it never expires, we don't have to queue the callback */
196     }
197     ReleaseWriteLock(&afs_xcbhash);
198     afs_ProcessFS(tvc, &OutFidStatus, &treq);
199
200     if (!tvc->linkData) {
201         tvc->linkData = (char *) afs_osi_Alloc(alen);
202         strncpy(tvc->linkData, atargetName, alen-1);
203         tvc->linkData[alen-1] = 0;
204     }
205     ReleaseWriteLock(&tvc->lock);
206     ReleaseWriteLock(&afs_xvcache);
207     afs_PutVCache(tvc, WRITE_LOCK);
208     code = 0;
209 done:
210 #ifdef  AFS_OSF_ENV
211     AFS_RELE(ndp->ni_dvp);
212 #endif  /* AFS_OSF_ENV */
213     if ( volp ) 
214         afs_PutVolume(volp, READ_LOCK);
215     code = afs_CheckCode(code, &treq, 31);
216     return code;
217 }
218
219 afs_MemHandleLink(avc, areq)
220      register struct vcache *avc;
221      struct vrequest *areq;
222   {
223       register struct dcache *tdc;
224       register char *tp;
225       afs_size_t offset, len;
226       afs_int32 tlen, alen;
227       register afs_int32 code;
228
229       AFS_STATCNT(afs_MemHandleLink);
230       /* two different formats, one for links protected 644, have a "." at
231          the end of the file name, which we turn into a null.  Others, 
232          protected 755, we add a null to the end of */
233       if (!avc->linkData) {
234           void *addr;
235           tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 0);
236           if (!tdc) {
237               return EIO;
238           }
239           /* otherwise we have the data loaded, go for it */
240           if (len > 1024) {
241               afs_PutDCache(tdc);
242               return EFAULT;
243           }
244           if (avc->m.Mode       & 0111) alen = len+1;   /* regular link */
245           else alen = len;                      /* mt point */
246           tp = afs_osi_Alloc(alen); /* make room for terminating null */
247           addr = afs_MemCacheOpen(tdc->f.inode);
248           tlen = len;
249           code = afs_MemReadBlk(addr, 0, tp, tlen);
250           tp[alen-1] = 0;
251           afs_PutDCache(tdc);
252           if (code != len) {
253               afs_osi_Free(tp, alen);
254               return EIO;
255           }
256           avc->linkData = tp;
257       }
258       return 0;
259   }
260
261 afs_UFSHandleLink(avc, areq)
262     register struct vcache *avc;
263     struct vrequest *areq; 
264 {
265     register struct dcache *tdc;
266     register char *tp;
267     char *tfile;
268     afs_size_t offset, len;
269     afs_int32 tlen, alen;
270     register afs_int32 code;
271
272     /* two different formats, one for links protected 644, have a "." at the end
273         of the file name, which we turn into a null.  Others, protected 755,
274         we add a null to the end of */
275    AFS_STATCNT(afs_UFSHandleLink);
276     if (!avc->linkData) {
277         tdc = afs_GetDCache(avc, (afs_size_t) 0, areq, &offset, &len, 0);
278         afs_Trace3(afs_iclSetp, CM_TRACE_UFSLINK, ICL_TYPE_POINTER, avc,
279                         ICL_TYPE_POINTER, tdc,
280                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
281         if (!tdc) {
282             return EIO;
283         }
284         /* otherwise we have the data loaded, go for it */
285         if (len > 1024) {
286             afs_PutDCache(tdc);
287             return EFAULT;
288         }
289         tfile = osi_UFSOpen (tdc->f.inode);
290         if (avc->m.Mode & 0111) alen = len+1;   /* regular link */
291         else alen = len;                        /* mt point */
292         tp = afs_osi_Alloc(alen);               /* make room for terminating null */
293         tlen = len;
294         code = afs_osi_Read(tfile, -1, tp, tlen);
295         tp[alen-1] = 0;
296         osi_UFSClose(tfile);
297         afs_PutDCache(tdc);
298         if (code != tlen) {
299             afs_osi_Free(tp, alen);
300             return EIO;
301         }
302         avc->linkData = tp;
303     }
304     return 0;
305 }
306
307 afs_readlink(OSI_VC_ARG(avc), auio, acred)
308     OSI_VC_DECL(avc);
309     struct uio *auio;
310     struct AFS_UCRED *acred; 
311 {
312     register afs_int32 code;
313     struct vrequest treq;
314     register char *tp;
315     OSI_VC_CONVERT(avc)
316
317     AFS_STATCNT(afs_readlink);
318     afs_Trace1(afs_iclSetp, CM_TRACE_READLINK, ICL_TYPE_POINTER, avc);
319     if (code = afs_InitReq(&treq, acred)) return code;
320     code = afs_VerifyVCache(avc, &treq);
321     if (code) goto done;
322     if (vType(avc) != VLNK) {
323         code = EINVAL;
324         goto done;
325     }
326     ObtainWriteLock(&avc->lock,158);
327     code = afs_HandleLink(avc, &treq);
328     /* finally uiomove it to user-land */
329     if (code == 0) {
330         tp = avc->linkData;
331         if (tp) AFS_UIOMOVE(tp, strlen(tp), UIO_READ, auio, code);
332         else {
333             code = EIO;
334         }
335     }
336     ReleaseWriteLock(&avc->lock);
337 done:
338     code = afs_CheckCode(code, &treq, 32);
339     return code;
340 }