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