This source file includes following definitions.
- vfs_getcwd_scandir
- vfs_getcwd_getcache
- vfs_getcwd_common
- proc_isunder
- sys___getcwd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/filedesc.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49 #include <sys/proc.h>
50 #include <sys/uio.h>
51 #include <sys/malloc.h>
52 #include <sys/dirent.h>
53 #include <ufs/ufs/dir.h>
54
55 #include <sys/syscallargs.h>
56
57 #define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN + 1) + 4)
58
59
60 int
61 vfs_getcwd_scandir(struct vnode **lvpp, struct vnode **uvpp, char **bpp,
62 char *bufp, struct proc *p)
63 {
64 int eofflag, tries, dirbuflen, len, reclen, error = 0;
65 off_t off;
66 struct uio uio;
67 struct iovec iov;
68 char *dirbuf = NULL;
69 ino_t fileno;
70 struct vattr va;
71 struct vnode *uvp = NULL;
72 struct vnode *lvp = *lvpp;
73 struct componentname cn;
74
75 tries = 0;
76
77
78
79
80
81 if (bufp != NULL) {
82 error = VOP_GETATTR(lvp, &va, p->p_ucred, p);
83 if (error) {
84 vput(lvp);
85 *lvpp = NULL;
86 *uvpp = NULL;
87 return (error);
88 }
89 }
90
91 cn.cn_nameiop = LOOKUP;
92 cn.cn_flags = ISLASTCN | ISDOTDOT | RDONLY;
93 cn.cn_proc = p;
94 cn.cn_cred = p->p_ucred;
95 cn.cn_pnbuf = NULL;
96 cn.cn_nameptr = "..";
97 cn.cn_namelen = 2;
98 cn.cn_hash = 0;
99 cn.cn_consume = 0;
100
101
102 error = VOP_LOOKUP(lvp, uvpp, &cn);
103 if (error) {
104 vput(lvp);
105 *lvpp = NULL;
106 *uvpp = NULL;
107 return (error);
108 }
109
110 uvp = *uvpp;
111
112
113 if (bufp == NULL) {
114 vrele(lvp);
115 *lvpp = NULL;
116 return (0);
117 }
118
119 fileno = va.va_fileid;
120
121 dirbuflen = DIRBLKSIZ;
122
123 if (dirbuflen < va.va_blocksize)
124 dirbuflen = va.va_blocksize;
125
126 dirbuf = malloc(dirbuflen, M_TEMP, M_WAITOK);
127
128 off = 0;
129
130 do {
131 char *cpos;
132 struct dirent *dp;
133
134 iov.iov_base = dirbuf;
135 iov.iov_len = dirbuflen;
136
137 uio.uio_iov = &iov;
138 uio.uio_iovcnt = 1;
139 uio.uio_offset = off;
140 uio.uio_resid = dirbuflen;
141 uio.uio_segflg = UIO_SYSSPACE;
142 uio.uio_rw = UIO_READ;
143 uio.uio_procp = p;
144
145 eofflag = 0;
146
147
148 error = VOP_READDIR(uvp, &uio, p->p_ucred, &eofflag, 0, 0);
149
150 off = uio.uio_offset;
151
152
153 if (error == EINVAL && tries < 3) {
154 tries++;
155 off = 0;
156 continue;
157 } else if (error) {
158 goto out;
159 }
160
161 cpos = dirbuf;
162 tries = 0;
163
164
165 for (len = (dirbuflen - uio.uio_resid); len > 0;
166 len -= reclen) {
167 dp = (struct dirent *)cpos;
168 reclen = dp->d_reclen;
169
170
171 if (reclen < DIRENT_MINSIZE) {
172 error = EINVAL;
173 goto out;
174 }
175
176 if (dp->d_fileno == fileno) {
177 char *bp = *bpp;
178 bp -= dp->d_namlen;
179
180 if (bp <= bufp) {
181 error = ERANGE;
182 goto out;
183 }
184
185 bcopy(dp->d_name, bp, dp->d_namlen);
186 error = 0;
187 *bpp = bp;
188
189 goto out;
190 }
191
192 cpos += reclen;
193 }
194
195 } while (!eofflag);
196
197 error = ENOENT;
198
199 out:
200
201 vrele(lvp);
202 *lvpp = NULL;
203
204 free(dirbuf, M_TEMP);
205
206 return (error);
207 }
208
209
210 int
211 vfs_getcwd_getcache(struct vnode **lvpp, struct vnode **uvpp, char **bpp,
212 char *bufp)
213 {
214 struct vnode *lvp, *uvp = NULL;
215 struct proc *p = curproc;
216 char *obp;
217 int error, vpid;
218
219 lvp = *lvpp;
220 obp = *bpp;
221
222 error = cache_revlookup(lvp, uvpp, bpp, bufp);
223 if (error) {
224 if (error != -1) {
225 vput(lvp);
226 *lvpp = NULL;
227 *uvpp = NULL;
228 }
229
230 return (error);
231 }
232
233 uvp = *uvpp;
234 vpid = uvp->v_id;
235
236
237
238 VOP_UNLOCK(lvp, 0, p);
239
240 error = vget(uvp, LK_EXCLUSIVE | LK_RETRY, p);
241 if (error)
242 *uvpp = NULL;
243
244
245
246
247
248 if (error || (vpid != uvp->v_id)) {
249
250
251
252
253 if (!error)
254 vput(uvp);
255
256 *uvpp = NULL;
257
258 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
259 if (!error) {
260 *bpp = obp;
261 return (-1);
262 }
263 }
264
265 vrele(lvp);
266 *lvpp = NULL;
267
268 return (error);
269 }
270
271 #define GETCWD_CHECK_ACCESS 0x0001
272
273
274 int
275 vfs_getcwd_common(struct vnode *lvp, struct vnode *rvp, char **bpp, char *bufp,
276 int limit, int flags, struct proc *p)
277 {
278 struct filedesc *fdp = p->p_fd;
279 struct vnode *uvp = NULL;
280 char *bp = NULL;
281 int error, perms = VEXEC;
282
283 if (rvp == NULL) {
284 rvp = fdp->fd_rdir;
285 if (rvp == NULL)
286 rvp = rootvnode;
287 }
288
289 VREF(rvp);
290 VREF(lvp);
291
292 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
293 if (error) {
294 vrele(lvp);
295 lvp = NULL;
296 goto out;
297 }
298
299 if (bufp)
300 bp = *bpp;
301
302 if (lvp == rvp) {
303 if (bp)
304 *(--bp) = '/';
305 goto out;
306 }
307
308
309
310
311
312 do {
313 if (lvp->v_type != VDIR) {
314 error = ENOTDIR;
315 goto out;
316 }
317
318
319 if (flags & GETCWD_CHECK_ACCESS) {
320 error = VOP_ACCESS(lvp, perms, p->p_ucred, p);
321 if (error)
322 goto out;
323 perms = VEXEC|VREAD;
324 }
325
326
327 while (lvp->v_flag & VROOT) {
328 struct vnode *tvp;
329
330 if (lvp == rvp)
331 goto out;
332
333 tvp = lvp;
334 lvp = lvp->v_mount->mnt_vnodecovered;
335
336 vput(tvp);
337
338 if (lvp == NULL) {
339 error = ENOENT;
340 goto out;
341 }
342
343 VREF(lvp);
344
345 error = vn_lock(lvp, LK_EXCLUSIVE | LK_RETRY, p);
346 if (error) {
347 vrele(lvp);
348 lvp = NULL;
349 goto out;
350 }
351 }
352
353
354 error = vfs_getcwd_getcache(&lvp, &uvp, &bp, bufp);
355
356 if (error == -1) {
357
358 error = vfs_getcwd_scandir(&lvp, &uvp, &bp, bufp, p);
359 }
360
361 if (error)
362 goto out;
363
364 #ifdef DIAGNOSTIC
365 if (lvp != NULL)
366 panic("getcwd: oops, forgot to null lvp");
367 if (bufp && (bp <= bufp)) {
368 panic("getcwd: oops, went back too far");
369 }
370 #endif
371
372 if (bp)
373 *(--bp) = '/';
374
375 lvp = uvp;
376 uvp = NULL;
377 limit--;
378
379 } while ((lvp != rvp) && (limit > 0));
380
381 out:
382
383 if (bpp)
384 *bpp = bp;
385
386 if (uvp)
387 vput(uvp);
388
389 if (lvp)
390 vput(lvp);
391
392 vrele(rvp);
393
394 return (error);
395 }
396
397
398 int
399 proc_isunder(struct proc *p1, struct proc *p2)
400 {
401 struct vnode *r1 = p1->p_fd->fd_rdir;
402 struct vnode *r2 = p2->p_fd->fd_rdir;
403
404 if (r1 == NULL)
405 return (r2 == NULL);
406
407 if (r2 == NULL)
408 return (1);
409
410 return (vn_isunder(r1, r2, p2));
411 }
412
413
414 int
415 sys___getcwd(struct proc *p, void *v, register_t *retval)
416 {
417 struct sys___getcwd_args *uap = v;
418 int error, lenused, len = SCARG(uap, len);
419 char *path, *bp, *bend;
420
421 if (len > MAXPATHLEN * 4)
422 len = MAXPATHLEN * 4;
423 else if (len < 2)
424 return (ERANGE);
425
426 path = malloc(len, M_TEMP, M_WAITOK);
427
428 bp = &path[len];
429 bend = bp;
430 *(--bp) = '\0';
431
432
433
434
435
436
437 error = vfs_getcwd_common(p->p_fd->fd_cdir, NULL, &bp, path, len/2,
438 GETCWD_CHECK_ACCESS, p);
439
440 if (error)
441 goto out;
442
443 lenused = bend - bp;
444 *retval = lenused;
445
446
447 error = copyout(bp, SCARG(uap, buf), lenused);
448
449 out:
450 free(path, M_TEMP);
451
452 return (error);
453 }