Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
fc2aed1e KM |
2 | * Copyright (c) 1989 The Regents of the University of California. |
3 | * All rights reserved. | |
da7c5cc6 | 4 | * |
fc2aed1e KM |
5 | * Redistribution and use in source and binary forms are permitted |
6 | * provided that the above copyright notice and this paragraph are | |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
16 | * | |
d7b2a16c | 17 | * @(#)vfs_syscalls.c 7.13 (Berkeley) %G% |
da7c5cc6 | 18 | */ |
6459ebe0 | 19 | |
94368568 JB |
20 | #include "param.h" |
21 | #include "systm.h" | |
fc2aed1e | 22 | #include "syscontext.h" |
94368568 JB |
23 | #include "kernel.h" |
24 | #include "file.h" | |
25 | #include "stat.h" | |
fc2aed1e KM |
26 | #include "vnode.h" |
27 | #include "../ufs/inode.h" | |
28 | #include "mount.h" | |
94368568 | 29 | #include "proc.h" |
94368568 | 30 | #include "uio.h" |
fc2aed1e | 31 | #include "malloc.h" |
88a7a62a | 32 | |
fc2aed1e KM |
33 | /* |
34 | * Virtual File System System Calls | |
35 | */ | |
3e78e260 | 36 | |
4f083fd7 | 37 | /* |
fc2aed1e | 38 | * mount system call |
4f083fd7 | 39 | */ |
fc2aed1e | 40 | mount() |
3e78e260 | 41 | { |
fc2aed1e KM |
42 | register struct a { |
43 | int type; | |
44 | char *dir; | |
45 | int flags; | |
46 | caddr_t data; | |
47 | } *uap = (struct a *)u.u_ap; | |
48 | register struct nameidata *ndp = &u.u_nd; | |
49 | struct vnode *vp; | |
50 | struct mount *mp; | |
51 | int error; | |
3e78e260 | 52 | |
fc2aed1e KM |
53 | /* |
54 | * Must be super user | |
55 | */ | |
56 | if (error = suser(u.u_cred, &u.u_acflag)) | |
57 | RETURN (error); | |
58 | /* | |
59 | * Get vnode to be covered | |
60 | */ | |
61 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
62 | ndp->ni_segflg = UIO_USERSPACE; | |
63 | ndp->ni_dirp = uap->dir; | |
64 | if (error = namei(ndp)) | |
65 | RETURN (error); | |
66 | vp = ndp->ni_vp; | |
67 | if (vp->v_count != 1) { | |
68 | vput(vp); | |
69 | RETURN (EBUSY); | |
70 | } | |
71 | if (vp->v_type != VDIR) { | |
72 | vput(vp); | |
73 | RETURN (ENOTDIR); | |
74 | } | |
75 | if (uap->type > MOUNT_MAXTYPE || | |
76 | vfssw[uap->type] == (struct vfsops *)0) { | |
77 | vput(vp); | |
78 | RETURN (ENODEV); | |
79 | } | |
80 | ||
81 | /* | |
82 | * Mount the filesystem. | |
83 | */ | |
84 | mp = (struct mount *)malloc((u_long)sizeof(struct mount), | |
85 | M_MOUNT, M_WAITOK); | |
86 | mp->m_op = vfssw[uap->type]; | |
87 | mp->m_flag = 0; | |
88 | mp->m_exroot = 0; | |
89 | error = vfs_add(vp, mp, uap->flags); | |
90 | if (!error) | |
91 | error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); | |
92 | cache_purge(vp); | |
93 | VOP_UNLOCK(vp); | |
94 | if (!error) { | |
95 | vfs_unlock(mp); | |
96 | } else { | |
97 | vfs_remove(mp); | |
98 | free((caddr_t)mp, M_MOUNT); | |
99 | vrele(vp); | |
100 | } | |
101 | RETURN (error); | |
3e78e260 BJ |
102 | } |
103 | ||
4f083fd7 | 104 | /* |
fc2aed1e KM |
105 | * Unmount system call. |
106 | * | |
107 | * Note: unmount takes a path to the vnode mounted on as argument, | |
108 | * not special file (as before). | |
4f083fd7 | 109 | */ |
fc2aed1e KM |
110 | unmount() |
111 | { | |
112 | struct a { | |
113 | char *pathp; | |
114 | int flags; | |
115 | } *uap = (struct a *)u.u_ap; | |
116 | register struct vnode *vp; | |
117 | register struct mount *mp; | |
118 | register struct nameidata *ndp = &u.u_nd; | |
119 | struct vnode *coveredvp; | |
120 | int error; | |
121 | ||
122 | /* | |
123 | * Must be super user | |
124 | */ | |
125 | if (error = suser(u.u_cred, &u.u_acflag)) | |
126 | RETURN (error); | |
127 | ||
128 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; | |
129 | ndp->ni_segflg = UIO_USERSPACE; | |
130 | ndp->ni_dirp = uap->pathp; | |
131 | if (error = namei(ndp)) | |
132 | RETURN (error); | |
133 | vp = ndp->ni_vp; | |
134 | /* | |
135 | * Must be the root of the filesystem | |
136 | */ | |
137 | if ((vp->v_flag & VROOT) == 0) { | |
138 | vput(vp); | |
139 | RETURN (EINVAL); | |
140 | } | |
141 | mp = vp->v_mount; | |
142 | vput(vp); | |
143 | /* | |
144 | * Do the unmount. | |
145 | */ | |
146 | coveredvp = mp->m_vnodecovered; | |
147 | if (error = vfs_lock(mp)) | |
148 | RETURN (error); | |
149 | ||
150 | xumount(mp); /* remove unused sticky files from text table */ | |
151 | cache_purgevfs(mp); /* remove cache entries for this file sys */ | |
152 | VFS_SYNC(mp, MNT_WAIT); | |
153 | ||
154 | error = VFS_UNMOUNT(mp, uap->flags); | |
155 | if (error) { | |
156 | vfs_unlock(mp); | |
157 | } else { | |
158 | vrele(coveredvp); | |
159 | vfs_remove(mp); | |
160 | free((caddr_t)mp, M_MOUNT); | |
161 | } | |
162 | RETURN (error); | |
163 | } | |
164 | ||
165 | /* | |
166 | * Sync system call. | |
167 | * Sync each mounted filesystem. | |
168 | */ | |
169 | sync() | |
3e78e260 | 170 | { |
fc2aed1e KM |
171 | register struct mount *mp; |
172 | ||
173 | mp = rootfs; | |
174 | do { | |
175 | if ((mp->m_flag & M_RDONLY) == 0) | |
176 | VFS_SYNC(mp, MNT_NOWAIT); | |
177 | mp = mp->m_next; | |
178 | } while (mp != rootfs); | |
179 | } | |
180 | ||
181 | /* | |
182 | * get filesystem statistics | |
183 | */ | |
184 | statfs() | |
185 | { | |
186 | struct a { | |
187 | char *path; | |
188 | struct statfs *buf; | |
189 | } *uap = (struct a *)u.u_ap; | |
190 | register struct vnode *vp; | |
191 | register struct nameidata *ndp = &u.u_nd; | |
192 | struct statfs sb; | |
193 | int error; | |
3e78e260 | 194 | |
fc2aed1e KM |
195 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
196 | ndp->ni_segflg = UIO_USERSPACE; | |
197 | ndp->ni_dirp = uap->path; | |
198 | if (error = namei(ndp)) | |
199 | RETURN (error); | |
200 | vp = ndp->ni_vp; | |
201 | if (error = VFS_STATFS(vp->v_mount, &sb)) | |
202 | goto out; | |
203 | error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); | |
204 | out: | |
205 | vput(vp); | |
206 | RETURN (error); | |
207 | } | |
208 | ||
209 | fstatfs() | |
210 | { | |
211 | struct a { | |
212 | int fd; | |
213 | struct statfs *buf; | |
214 | } *uap = (struct a *)u.u_ap; | |
215 | struct file *fp; | |
216 | struct statfs sb; | |
217 | int error; | |
218 | ||
219 | if (error = getvnode(uap->fd, &fp)) | |
220 | RETURN (error); | |
221 | if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) | |
222 | RETURN (error); | |
223 | RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); | |
3e78e260 BJ |
224 | } |
225 | ||
bfcdbfbf KM |
226 | /* |
227 | * get statistics on all filesystems | |
228 | */ | |
229 | getfsstat() | |
230 | { | |
231 | struct a { | |
232 | struct statfs *buf; | |
233 | long bufsize; | |
234 | } *uap = (struct a *)u.u_ap; | |
235 | register struct mount *mp; | |
236 | register struct statfs *sfsp; | |
237 | long count, maxcount, error; | |
238 | ||
239 | maxcount = uap->bufsize / sizeof(struct statfs); | |
240 | sfsp = uap->buf; | |
241 | mp = rootfs; | |
242 | count = 0; | |
243 | do { | |
244 | count++; | |
245 | if (sfsp && count <= maxcount) { | |
246 | if (error = VFS_STATFS(mp, sfsp)) | |
247 | RETURN (error); | |
248 | sfsp++; | |
249 | } | |
250 | mp = mp->m_prev; | |
251 | } while (mp != rootfs); | |
252 | if (sfsp && count > maxcount) | |
253 | u.u_r.r_val1 = maxcount; | |
254 | else | |
255 | u.u_r.r_val1 = count; | |
256 | RETURN (0); | |
257 | } | |
258 | ||
6995a2cb KM |
259 | /* |
260 | * Change current working directory to a given file descriptor. | |
261 | */ | |
262 | fchdir() | |
263 | { | |
264 | struct a { | |
265 | int fd; | |
266 | } *uap = (struct a *)u.u_ap; | |
267 | register struct vnode *vp; | |
268 | struct file *fp; | |
269 | int error; | |
270 | ||
271 | if (error = getvnode(uap->fd, &fp)) | |
272 | RETURN (error); | |
273 | vp = (struct vnode *)fp->f_data; | |
274 | VOP_LOCK(vp); | |
275 | if (vp->v_type != VDIR) | |
276 | error = ENOTDIR; | |
277 | else | |
d7b2a16c | 278 | error = VOP_ACCESS(vp, VEXEC, u.u_cred); |
6995a2cb KM |
279 | VOP_UNLOCK(vp); |
280 | vrele(u.u_cdir); | |
281 | u.u_cdir = vp; | |
282 | RETURN (error); | |
283 | } | |
284 | ||
4f083fd7 | 285 | /* |
fc2aed1e | 286 | * Change current working directory (``.''). |
4f083fd7 | 287 | */ |
fc2aed1e | 288 | chdir() |
3e78e260 | 289 | { |
3e78e260 BJ |
290 | struct a { |
291 | char *fname; | |
715baff1 KM |
292 | } *uap = (struct a *)u.u_ap; |
293 | register struct nameidata *ndp = &u.u_nd; | |
fc2aed1e | 294 | int error; |
3e78e260 | 295 | |
fc2aed1e | 296 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
297 | ndp->ni_segflg = UIO_USERSPACE; |
298 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
299 | if (error = chdirec(ndp)) |
300 | RETURN (error); | |
301 | vrele(u.u_cdir); | |
302 | u.u_cdir = ndp->ni_vp; | |
303 | RETURN (0); | |
304 | } | |
305 | ||
306 | /* | |
307 | * Change notion of root (``/'') directory. | |
308 | */ | |
309 | chroot() | |
310 | { | |
311 | struct a { | |
312 | char *fname; | |
313 | } *uap = (struct a *)u.u_ap; | |
314 | register struct nameidata *ndp = &u.u_nd; | |
315 | int error; | |
316 | ||
317 | if (error = suser(u.u_cred, &u.u_acflag)) | |
318 | RETURN (error); | |
319 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
320 | ndp->ni_segflg = UIO_USERSPACE; | |
321 | ndp->ni_dirp = uap->fname; | |
322 | if (error = chdirec(ndp)) | |
323 | RETURN (error); | |
324 | vrele(u.u_rdir); | |
325 | u.u_rdir = ndp->ni_vp; | |
326 | RETURN (0); | |
327 | } | |
328 | ||
329 | /* | |
330 | * Common routine for chroot and chdir. | |
331 | */ | |
332 | chdirec(ndp) | |
333 | register struct nameidata *ndp; | |
334 | { | |
335 | struct vnode *vp; | |
336 | int error; | |
337 | ||
338 | if (error = namei(ndp)) | |
339 | return (error); | |
340 | vp = ndp->ni_vp; | |
341 | if (vp->v_type != VDIR) | |
342 | error = ENOTDIR; | |
343 | else | |
d7b2a16c | 344 | error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); |
fc2aed1e KM |
345 | VOP_UNLOCK(vp); |
346 | if (error) | |
347 | vrele(vp); | |
348 | return (error); | |
3e78e260 BJ |
349 | } |
350 | ||
351 | /* | |
352 | * Open system call. | |
353 | */ | |
354 | open() | |
355 | { | |
88a7a62a | 356 | struct a { |
3e78e260 | 357 | char *fname; |
528f664c | 358 | int mode; |
88a7a62a SL |
359 | int crtmode; |
360 | } *uap = (struct a *) u.u_ap; | |
fc2aed1e | 361 | struct nameidata *ndp = &u.u_nd; |
3e78e260 | 362 | |
fc2aed1e KM |
363 | ndp->ni_segflg = UIO_USERSPACE; |
364 | ndp->ni_dirp = uap->fname; | |
365 | RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp, | |
366 | &u.u_r.r_val1)); | |
3e78e260 BJ |
367 | } |
368 | ||
369 | /* | |
370 | * Creat system call. | |
371 | */ | |
88a7a62a | 372 | creat() |
3e78e260 | 373 | { |
88a7a62a | 374 | struct a { |
3e78e260 BJ |
375 | char *fname; |
376 | int fmode; | |
88a7a62a | 377 | } *uap = (struct a *)u.u_ap; |
fc2aed1e | 378 | struct nameidata *ndp = &u.u_nd; |
3e78e260 | 379 | |
fc2aed1e KM |
380 | ndp->ni_segflg = UIO_USERSPACE; |
381 | ndp->ni_dirp = uap->fname; | |
382 | RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp, | |
383 | &u.u_r.r_val1)); | |
3e78e260 BJ |
384 | } |
385 | ||
386 | /* | |
387 | * Common code for open and creat. | |
88a7a62a SL |
388 | * Check permissions, allocate an open file structure, |
389 | * and call the device open routine if any. | |
3e78e260 | 390 | */ |
fc2aed1e KM |
391 | copen(fmode, cmode, ndp, resultfd) |
392 | int fmode, cmode; | |
393 | struct nameidata *ndp; | |
394 | int *resultfd; | |
3e78e260 BJ |
395 | { |
396 | register struct file *fp; | |
fc2aed1e KM |
397 | struct file *nfp; |
398 | int indx, error; | |
399 | extern struct fileops vnops; | |
400 | ||
401 | if (error = falloc(&nfp, &indx)) | |
402 | return (error); | |
403 | fp = nfp; | |
404 | u.u_r.r_val1 = indx; /* XXX for fdopen() */ | |
405 | if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { | |
49873122 | 406 | u.u_ofile[indx] = NULL; |
fc2aed1e KM |
407 | crfree(fp->f_cred); |
408 | fp->f_count--; | |
409 | return (error); | |
528f664c | 410 | } |
fc2aed1e KM |
411 | fp->f_flag = fmode & FMASK; |
412 | fp->f_type = DTYPE_VNODE; | |
413 | fp->f_ops = &vnops; | |
414 | fp->f_data = (caddr_t)ndp->ni_vp; | |
415 | if (resultfd) | |
416 | *resultfd = indx; | |
417 | return (0); | |
3e78e260 BJ |
418 | } |
419 | ||
420 | /* | |
421 | * Mknod system call | |
422 | */ | |
423 | mknod() | |
424 | { | |
3e78e260 BJ |
425 | register struct a { |
426 | char *fname; | |
427 | int fmode; | |
428 | int dev; | |
715baff1 KM |
429 | } *uap = (struct a *)u.u_ap; |
430 | register struct nameidata *ndp = &u.u_nd; | |
fc2aed1e KM |
431 | register struct vnode *vp; |
432 | struct vattr vattr; | |
433 | int error; | |
3e78e260 | 434 | |
fc2aed1e KM |
435 | if (error = suser(u.u_cred, &u.u_acflag)) |
436 | RETURN (error); | |
437 | ndp->ni_nameiop = CREATE | LOCKPARENT; | |
715baff1 KM |
438 | ndp->ni_segflg = UIO_USERSPACE; |
439 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
440 | if (error = namei(ndp)) |
441 | RETURN (error); | |
442 | vp = ndp->ni_vp; | |
443 | if (vp != NULL) { | |
444 | error = EEXIST; | |
88a7a62a | 445 | goto out; |
3e78e260 | 446 | } |
fc2aed1e KM |
447 | vattr_null(&vattr); |
448 | switch (uap->fmode & IFMT) { | |
88a7a62a | 449 | |
7bfaea72 | 450 | case IFMT: /* used by badsect to flag bad sectors */ |
fc2aed1e KM |
451 | vattr.va_type = VBAD; |
452 | break; | |
88a7a62a | 453 | case IFCHR: |
fc2aed1e KM |
454 | vattr.va_type = VCHR; |
455 | break; | |
88a7a62a | 456 | case IFBLK: |
fc2aed1e KM |
457 | vattr.va_type = VBLK; |
458 | break; | |
459 | default: | |
460 | error = EINVAL; | |
461 | goto out; | |
3e78e260 | 462 | } |
fc2aed1e KM |
463 | vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; |
464 | vattr.va_rdev = uap->dev; | |
3e78e260 | 465 | out: |
fc2aed1e KM |
466 | if (error) |
467 | VOP_ABORTOP(ndp); | |
468 | else | |
469 | error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); | |
470 | RETURN (error); | |
3e78e260 BJ |
471 | } |
472 | ||
473 | /* | |
474 | * link system call | |
475 | */ | |
476 | link() | |
477 | { | |
3e78e260 BJ |
478 | register struct a { |
479 | char *target; | |
480 | char *linkname; | |
715baff1 KM |
481 | } *uap = (struct a *)u.u_ap; |
482 | register struct nameidata *ndp = &u.u_nd; | |
fc2aed1e KM |
483 | register struct vnode *vp, *xp; |
484 | int error; | |
3e78e260 | 485 | |
715baff1 KM |
486 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
487 | ndp->ni_segflg = UIO_USERSPACE; | |
488 | ndp->ni_dirp = uap->target; | |
fc2aed1e KM |
489 | if (error = namei(ndp)) |
490 | RETURN (error); | |
491 | vp = ndp->ni_vp; | |
492 | if (vp->v_type == VDIR && | |
493 | (error = suser(u.u_cred, &u.u_acflag))) | |
494 | goto out1; | |
495 | ndp->ni_nameiop = CREATE | LOCKPARENT; | |
715baff1 | 496 | ndp->ni_dirp = (caddr_t)uap->linkname; |
fc2aed1e KM |
497 | if (error = namei(ndp)) |
498 | goto out1; | |
499 | xp = ndp->ni_vp; | |
3e78e260 | 500 | if (xp != NULL) { |
fc2aed1e | 501 | error = EEXIST; |
3e78e260 BJ |
502 | goto out; |
503 | } | |
fc2aed1e KM |
504 | xp = ndp->ni_dvp; |
505 | if (vp->v_mount != xp->v_mount) | |
506 | error = EXDEV; | |
3e78e260 | 507 | out: |
fc2aed1e KM |
508 | if (error) |
509 | VOP_ABORTOP(ndp); | |
510 | else | |
511 | error = VOP_LINK(vp, ndp); | |
512 | out1: | |
513 | vrele(vp); | |
514 | RETURN (error); | |
3e78e260 BJ |
515 | } |
516 | ||
517 | /* | |
518 | * symlink -- make a symbolic link | |
519 | */ | |
520 | symlink() | |
521 | { | |
fc2aed1e | 522 | struct a { |
3e78e260 BJ |
523 | char *target; |
524 | char *linkname; | |
715baff1 | 525 | } *uap = (struct a *)u.u_ap; |
715baff1 | 526 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
527 | register struct vnode *vp; |
528 | struct vattr vattr; | |
529 | char *target; | |
530 | int error; | |
3e78e260 | 531 | |
715baff1 KM |
532 | ndp->ni_segflg = UIO_USERSPACE; |
533 | ndp->ni_dirp = uap->linkname; | |
fc2aed1e KM |
534 | MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); |
535 | if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) | |
536 | goto out1; | |
537 | ndp->ni_nameiop = CREATE | LOCKPARENT; | |
538 | if (error = namei(ndp)) | |
539 | goto out1; | |
540 | vp = ndp->ni_vp; | |
541 | if (vp) { | |
542 | error = EEXIST; | |
543 | goto out; | |
3e78e260 | 544 | } |
fc2aed1e KM |
545 | vp = ndp->ni_dvp; |
546 | vattr_null(&vattr); | |
547 | vattr.va_mode = 0777 &~ u.u_cmask; | |
548 | out: | |
549 | if (error) | |
550 | VOP_ABORTOP(ndp); | |
551 | else | |
552 | error = VOP_SYMLINK(ndp, &vattr, target); | |
553 | out1: | |
554 | FREE(target, M_NAMEI); | |
555 | RETURN (error); | |
3e78e260 BJ |
556 | } |
557 | ||
558 | /* | |
559 | * Unlink system call. | |
560 | * Hard to avoid races here, especially | |
561 | * in unlinking directories. | |
562 | */ | |
563 | unlink() | |
564 | { | |
3e78e260 BJ |
565 | struct a { |
566 | char *fname; | |
715baff1 | 567 | } *uap = (struct a *)u.u_ap; |
715baff1 | 568 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
569 | register struct vnode *vp; |
570 | int error; | |
3e78e260 | 571 | |
fc2aed1e | 572 | ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; |
715baff1 KM |
573 | ndp->ni_segflg = UIO_USERSPACE; |
574 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
575 | if (error = namei(ndp)) |
576 | RETURN (error); | |
577 | vp = ndp->ni_vp; | |
578 | if (vp->v_type == VDIR && | |
579 | (error = suser(u.u_cred, &u.u_acflag))) | |
3e78e260 BJ |
580 | goto out; |
581 | /* | |
582 | * Don't unlink a mounted file. | |
583 | */ | |
fc2aed1e KM |
584 | if (vp->v_flag & VROOT) { |
585 | error = EBUSY; | |
3e78e260 BJ |
586 | goto out; |
587 | } | |
fc2aed1e KM |
588 | if (vp->v_flag & VTEXT) |
589 | xrele(vp); /* try once to free text */ | |
3e78e260 | 590 | out: |
fc2aed1e KM |
591 | if (error) |
592 | VOP_ABORTOP(ndp); | |
8eee8525 | 593 | else |
fc2aed1e KM |
594 | error = VOP_REMOVE(ndp); |
595 | RETURN (error); | |
3e78e260 BJ |
596 | } |
597 | ||
598 | /* | |
599 | * Seek system call | |
600 | */ | |
35e7c31a | 601 | lseek() |
3e78e260 BJ |
602 | { |
603 | register struct file *fp; | |
604 | register struct a { | |
fc2aed1e | 605 | int fdes; |
3e78e260 BJ |
606 | off_t off; |
607 | int sbase; | |
715baff1 | 608 | } *uap = (struct a *)u.u_ap; |
fc2aed1e KM |
609 | struct vattr vattr; |
610 | int error; | |
611 | ||
612 | if ((unsigned)uap->fdes >= NOFILE || | |
613 | (fp = u.u_ofile[uap->fdes]) == NULL) | |
614 | RETURN (EBADF); | |
615 | if (fp->f_type != DTYPE_VNODE) | |
616 | RETURN (ESPIPE); | |
b4d1aee9 SL |
617 | switch (uap->sbase) { |
618 | ||
619 | case L_INCR: | |
620 | fp->f_offset += uap->off; | |
621 | break; | |
622 | ||
623 | case L_XTND: | |
fc2aed1e KM |
624 | if (error = VOP_GETATTR((struct vnode *)fp->f_data, |
625 | &vattr, u.u_cred)) | |
626 | RETURN (error); | |
627 | fp->f_offset = uap->off + vattr.va_size; | |
b4d1aee9 SL |
628 | break; |
629 | ||
630 | case L_SET: | |
631 | fp->f_offset = uap->off; | |
632 | break; | |
633 | ||
634 | default: | |
fc2aed1e | 635 | RETURN (EINVAL); |
b4d1aee9 SL |
636 | } |
637 | u.u_r.r_off = fp->f_offset; | |
fc2aed1e | 638 | RETURN (0); |
3e78e260 BJ |
639 | } |
640 | ||
641 | /* | |
642 | * Access system call | |
643 | */ | |
644 | saccess() | |
645 | { | |
3e78e260 BJ |
646 | register struct a { |
647 | char *fname; | |
648 | int fmode; | |
715baff1 KM |
649 | } *uap = (struct a *)u.u_ap; |
650 | register struct nameidata *ndp = &u.u_nd; | |
fc2aed1e KM |
651 | register struct vnode *vp; |
652 | int error, mode, svuid, svgid; | |
3e78e260 | 653 | |
3e78e260 BJ |
654 | svuid = u.u_uid; |
655 | svgid = u.u_gid; | |
656 | u.u_uid = u.u_ruid; | |
657 | u.u_gid = u.u_rgid; | |
fc2aed1e | 658 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
659 | ndp->ni_segflg = UIO_USERSPACE; |
660 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
661 | if (error = namei(ndp)) |
662 | goto out1; | |
663 | vp = ndp->ni_vp; | |
664 | /* | |
665 | * fmode == 0 means only check for exist | |
666 | */ | |
667 | if (uap->fmode) { | |
668 | mode = 0; | |
669 | if (uap->fmode & R_OK) | |
670 | mode |= VREAD; | |
671 | if (uap->fmode & W_OK) | |
672 | mode |= VWRITE; | |
673 | if (uap->fmode & X_OK) | |
674 | mode |= VEXEC; | |
d7b2a16c KM |
675 | if ((error = vn_writechk(vp)) == 0) |
676 | error = VOP_ACCESS(vp, mode, ndp->ni_cred); | |
3e78e260 | 677 | } |
fc2aed1e KM |
678 | vput(vp); |
679 | out1: | |
3e78e260 BJ |
680 | u.u_uid = svuid; |
681 | u.u_gid = svgid; | |
fc2aed1e | 682 | RETURN (error); |
3e78e260 | 683 | } |
d67a03eb | 684 | |
d67a03eb | 685 | /* |
6459ebe0 | 686 | * Stat system call. This version follows links. |
d67a03eb BJ |
687 | */ |
688 | stat() | |
689 | { | |
d67a03eb | 690 | |
715baff1 | 691 | stat1(FOLLOW); |
d67a03eb BJ |
692 | } |
693 | ||
5485e062 | 694 | /* |
6459ebe0 | 695 | * Lstat system call. This version does not follow links. |
5485e062 BJ |
696 | */ |
697 | lstat() | |
88a7a62a SL |
698 | { |
699 | ||
715baff1 | 700 | stat1(NOFOLLOW); |
88a7a62a SL |
701 | } |
702 | ||
703 | stat1(follow) | |
704 | int follow; | |
5485e062 | 705 | { |
5485e062 BJ |
706 | register struct a { |
707 | char *fname; | |
88a7a62a | 708 | struct stat *ub; |
715baff1 | 709 | } *uap = (struct a *)u.u_ap; |
715baff1 | 710 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
711 | struct stat sb; |
712 | int error; | |
5485e062 | 713 | |
fc2aed1e | 714 | ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; |
715baff1 KM |
715 | ndp->ni_segflg = UIO_USERSPACE; |
716 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
717 | if (error = namei(ndp)) |
718 | RETURN (error); | |
719 | error = vn_stat(ndp->ni_vp, &sb); | |
720 | vput(ndp->ni_vp); | |
721 | if (error) | |
722 | RETURN (error); | |
723 | error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); | |
724 | RETURN (error); | |
d67a03eb BJ |
725 | } |
726 | ||
727 | /* | |
5485e062 BJ |
728 | * Return target name of a symbolic link |
729 | */ | |
730 | readlink() | |
731 | { | |
5485e062 BJ |
732 | register struct a { |
733 | char *name; | |
734 | char *buf; | |
735 | int count; | |
31949305 | 736 | } *uap = (struct a *)u.u_ap; |
715baff1 | 737 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
738 | register struct vnode *vp; |
739 | struct iovec aiov; | |
740 | struct uio auio; | |
741 | int error; | |
5485e062 | 742 | |
fc2aed1e | 743 | ndp->ni_nameiop = LOOKUP | LOCKLEAF; |
715baff1 KM |
744 | ndp->ni_segflg = UIO_USERSPACE; |
745 | ndp->ni_dirp = uap->name; | |
fc2aed1e KM |
746 | if (error = namei(ndp)) |
747 | RETURN (error); | |
748 | vp = ndp->ni_vp; | |
749 | if (vp->v_type != VLNK) { | |
750 | error = EINVAL; | |
5485e062 BJ |
751 | goto out; |
752 | } | |
fc2aed1e KM |
753 | aiov.iov_base = uap->buf; |
754 | aiov.iov_len = uap->count; | |
755 | auio.uio_iov = &aiov; | |
756 | auio.uio_iovcnt = 1; | |
757 | auio.uio_offset = 0; | |
758 | auio.uio_rw = UIO_READ; | |
759 | auio.uio_segflg = UIO_USERSPACE; | |
760 | auio.uio_resid = uap->count; | |
761 | error = VOP_READLINK(vp, &auio, ndp->ni_cred); | |
5485e062 | 762 | out: |
fc2aed1e KM |
763 | vput(vp); |
764 | u.u_r.r_val1 = uap->count - auio.uio_resid; | |
765 | RETURN (error); | |
5485e062 BJ |
766 | } |
767 | ||
6995a2cb KM |
768 | /* |
769 | * Change flags of a file given path name. | |
770 | */ | |
771 | chflags() | |
772 | { | |
773 | struct a { | |
774 | char *fname; | |
775 | int flags; | |
776 | } *uap = (struct a *)u.u_ap; | |
777 | register struct nameidata *ndp = &u.u_nd; | |
778 | register struct vnode *vp; | |
779 | struct vattr vattr; | |
780 | int error; | |
781 | ||
782 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
783 | ndp->ni_segflg = UIO_USERSPACE; | |
784 | ndp->ni_dirp = uap->fname; | |
785 | vattr_null(&vattr); | |
786 | vattr.va_flags = uap->flags; | |
787 | if (error = namei(ndp)) | |
788 | RETURN (error); | |
789 | vp = ndp->ni_vp; | |
790 | if (vp->v_mount->m_flag & M_RDONLY) { | |
791 | error = EROFS; | |
792 | goto out; | |
793 | } | |
794 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); | |
795 | out: | |
796 | vput(vp); | |
797 | RETURN (error); | |
798 | } | |
799 | ||
800 | /* | |
801 | * Change flags of a file given a file descriptor. | |
802 | */ | |
803 | fchflags() | |
804 | { | |
805 | struct a { | |
806 | int fd; | |
807 | int flags; | |
808 | } *uap = (struct a *)u.u_ap; | |
809 | struct vattr vattr; | |
810 | struct vnode *vp; | |
811 | struct file *fp; | |
812 | int error; | |
813 | ||
814 | if (error = getvnode(uap->fd, &fp)) | |
815 | RETURN (error); | |
816 | vattr_null(&vattr); | |
817 | vattr.va_flags = uap->flags; | |
818 | vp = (struct vnode *)fp->f_data; | |
819 | VOP_LOCK(vp); | |
820 | if (vp->v_mount->m_flag & M_RDONLY) { | |
821 | error = EROFS; | |
822 | goto out; | |
823 | } | |
824 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); | |
825 | out: | |
826 | VOP_UNLOCK(vp); | |
827 | RETURN (error); | |
828 | } | |
829 | ||
4f083fd7 SL |
830 | /* |
831 | * Change mode of a file given path name. | |
832 | */ | |
3e78e260 | 833 | chmod() |
5485e062 | 834 | { |
528f664c | 835 | struct a { |
3e78e260 BJ |
836 | char *fname; |
837 | int fmode; | |
715baff1 | 838 | } *uap = (struct a *)u.u_ap; |
fc2aed1e KM |
839 | register struct nameidata *ndp = &u.u_nd; |
840 | register struct vnode *vp; | |
841 | struct vattr vattr; | |
842 | int error; | |
5485e062 | 843 | |
fc2aed1e KM |
844 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
845 | ndp->ni_segflg = UIO_USERSPACE; | |
846 | ndp->ni_dirp = uap->fname; | |
847 | vattr_null(&vattr); | |
848 | vattr.va_mode = uap->fmode & 07777; | |
849 | if (error = namei(ndp)) | |
850 | RETURN (error); | |
851 | vp = ndp->ni_vp; | |
852 | if (vp->v_mount->m_flag & M_RDONLY) { | |
853 | error = EROFS; | |
854 | goto out; | |
855 | } | |
856 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); | |
857 | out: | |
858 | vput(vp); | |
859 | RETURN (error); | |
528f664c | 860 | } |
f94ceb3b | 861 | |
4f083fd7 SL |
862 | /* |
863 | * Change mode of a file given a file descriptor. | |
864 | */ | |
528f664c SL |
865 | fchmod() |
866 | { | |
867 | struct a { | |
868 | int fd; | |
869 | int fmode; | |
715baff1 | 870 | } *uap = (struct a *)u.u_ap; |
fc2aed1e KM |
871 | struct vattr vattr; |
872 | struct vnode *vp; | |
873 | struct file *fp; | |
874 | int error; | |
875 | ||
876 | if (error = getvnode(uap->fd, &fp)) | |
877 | RETURN (error); | |
878 | vattr_null(&vattr); | |
879 | vattr.va_mode = uap->fmode & 07777; | |
880 | vp = (struct vnode *)fp->f_data; | |
881 | VOP_LOCK(vp); | |
882 | if (vp->v_mount->m_flag & M_RDONLY) { | |
883 | error = EROFS; | |
884 | goto out; | |
f94ceb3b | 885 | } |
fc2aed1e KM |
886 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); |
887 | out: | |
888 | VOP_UNLOCK(vp); | |
889 | RETURN (error); | |
5485e062 BJ |
890 | } |
891 | ||
4f083fd7 SL |
892 | /* |
893 | * Set ownership given a path name. | |
894 | */ | |
3e78e260 | 895 | chown() |
d67a03eb | 896 | { |
528f664c | 897 | struct a { |
3e78e260 BJ |
898 | char *fname; |
899 | int uid; | |
900 | int gid; | |
715baff1 | 901 | } *uap = (struct a *)u.u_ap; |
18b0bce6 | 902 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
903 | register struct vnode *vp; |
904 | struct vattr vattr; | |
905 | int error; | |
d67a03eb | 906 | |
fc2aed1e | 907 | ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; |
18b0bce6 KB |
908 | ndp->ni_segflg = UIO_USERSPACE; |
909 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
910 | vattr_null(&vattr); |
911 | vattr.va_uid = uap->uid; | |
912 | vattr.va_gid = uap->gid; | |
913 | if (error = namei(ndp)) | |
914 | RETURN (error); | |
915 | vp = ndp->ni_vp; | |
916 | if (vp->v_mount->m_flag & M_RDONLY) { | |
917 | error = EROFS; | |
918 | goto out; | |
919 | } | |
920 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); | |
921 | out: | |
922 | vput(vp); | |
923 | RETURN (error); | |
528f664c | 924 | } |
f94ceb3b | 925 | |
4f083fd7 SL |
926 | /* |
927 | * Set ownership given a file descriptor. | |
928 | */ | |
528f664c SL |
929 | fchown() |
930 | { | |
931 | struct a { | |
932 | int fd; | |
933 | int uid; | |
934 | int gid; | |
715baff1 | 935 | } *uap = (struct a *)u.u_ap; |
fc2aed1e KM |
936 | struct vattr vattr; |
937 | struct vnode *vp; | |
938 | struct file *fp; | |
939 | int error; | |
940 | ||
941 | if (error = getvnode(uap->fd, &fp)) | |
942 | RETURN (error); | |
943 | vattr_null(&vattr); | |
944 | vattr.va_uid = uap->uid; | |
945 | vattr.va_gid = uap->gid; | |
946 | vp = (struct vnode *)fp->f_data; | |
947 | VOP_LOCK(vp); | |
948 | if (vp->v_mount->m_flag & M_RDONLY) { | |
949 | error = EROFS; | |
950 | goto out; | |
951 | } | |
952 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); | |
953 | out: | |
954 | VOP_UNLOCK(vp); | |
955 | RETURN (error); | |
d67a03eb BJ |
956 | } |
957 | ||
bb1b75f4 SL |
958 | utimes() |
959 | { | |
960 | register struct a { | |
961 | char *fname; | |
962 | struct timeval *tptr; | |
963 | } *uap = (struct a *)u.u_ap; | |
fc2aed1e KM |
964 | register struct nameidata *ndp = &u.u_nd; |
965 | register struct vnode *vp; | |
bb1b75f4 | 966 | struct timeval tv[2]; |
fc2aed1e KM |
967 | struct vattr vattr; |
968 | int error; | |
bb1b75f4 | 969 | |
fc2aed1e KM |
970 | if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) |
971 | RETURN (error); | |
972 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; | |
973 | ndp->ni_segflg = UIO_USERSPACE; | |
974 | ndp->ni_dirp = uap->fname; | |
975 | vattr_null(&vattr); | |
976 | vattr.va_atime = tv[0]; | |
977 | vattr.va_mtime = tv[1]; | |
978 | if (error = namei(ndp)) | |
979 | RETURN (error); | |
980 | vp = ndp->ni_vp; | |
981 | if (vp->v_mount->m_flag & M_RDONLY) { | |
982 | error = EROFS; | |
983 | goto out; | |
bb1b75f4 | 984 | } |
fc2aed1e KM |
985 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); |
986 | out: | |
987 | vput(vp); | |
988 | RETURN (error); | |
d67a03eb | 989 | } |
64d3a787 | 990 | |
4f083fd7 SL |
991 | /* |
992 | * Truncate a file given its path name. | |
993 | */ | |
528f664c SL |
994 | truncate() |
995 | { | |
996 | struct a { | |
997 | char *fname; | |
c979c6ce | 998 | off_t length; |
31949305 | 999 | } *uap = (struct a *)u.u_ap; |
715baff1 | 1000 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
1001 | register struct vnode *vp; |
1002 | struct vattr vattr; | |
1003 | int error; | |
528f664c | 1004 | |
fc2aed1e | 1005 | ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; |
715baff1 KM |
1006 | ndp->ni_segflg = UIO_USERSPACE; |
1007 | ndp->ni_dirp = uap->fname; | |
fc2aed1e KM |
1008 | vattr_null(&vattr); |
1009 | vattr.va_size = uap->length; | |
1010 | if (error = namei(ndp)) | |
1011 | RETURN (error); | |
1012 | vp = ndp->ni_vp; | |
1013 | if (vp->v_type == VDIR) { | |
1014 | error = EISDIR; | |
1015 | goto out; | |
528f664c | 1016 | } |
d7b2a16c KM |
1017 | if ((error = vn_writechk(vp)) || |
1018 | (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) | |
fc2aed1e KM |
1019 | goto out; |
1020 | error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); | |
1021 | out: | |
1022 | vput(vp); | |
1023 | RETURN (error); | |
528f664c SL |
1024 | } |
1025 | ||
4f083fd7 SL |
1026 | /* |
1027 | * Truncate a file given a file descriptor. | |
1028 | */ | |
528f664c SL |
1029 | ftruncate() |
1030 | { | |
1031 | struct a { | |
1032 | int fd; | |
c979c6ce | 1033 | off_t length; |
31949305 | 1034 | } *uap = (struct a *)u.u_ap; |
fc2aed1e KM |
1035 | struct vattr vattr; |
1036 | struct vnode *vp; | |
528f664c | 1037 | struct file *fp; |
fc2aed1e KM |
1038 | int error; |
1039 | ||
1040 | if (error = getvnode(uap->fd, &fp)) | |
1041 | RETURN (error); | |
1042 | if ((fp->f_flag & FWRITE) == 0) | |
1043 | RETURN (EINVAL); | |
1044 | vattr_null(&vattr); | |
1045 | vattr.va_size = uap->length; | |
1046 | vp = (struct vnode *)fp->f_data; | |
1047 | VOP_LOCK(vp); | |
1048 | if (vp->v_type == VDIR) { | |
1049 | error = EISDIR; | |
1050 | goto out; | |
528f664c | 1051 | } |
d7b2a16c | 1052 | if (error = vn_writechk(vp)) |
fc2aed1e KM |
1053 | goto out; |
1054 | error = VOP_SETATTR(vp, &vattr, fp->f_cred); | |
1055 | out: | |
1056 | VOP_UNLOCK(vp); | |
1057 | RETURN (error); | |
4f083fd7 SL |
1058 | } |
1059 | ||
1060 | /* | |
1061 | * Synch an open file. | |
1062 | */ | |
1063 | fsync() | |
1064 | { | |
1065 | struct a { | |
1066 | int fd; | |
1067 | } *uap = (struct a *)u.u_ap; | |
4f083fd7 | 1068 | struct file *fp; |
fc2aed1e | 1069 | int error; |
4f083fd7 | 1070 | |
fc2aed1e KM |
1071 | if (error = getvnode(uap->fd, &fp)) |
1072 | RETURN (error); | |
1073 | error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); | |
1074 | RETURN (error); | |
528f664c SL |
1075 | } |
1076 | ||
4f083fd7 SL |
1077 | /* |
1078 | * Rename system call. | |
4f083fd7 SL |
1079 | * |
1080 | * Source and destination must either both be directories, or both | |
1081 | * not be directories. If target is a directory, it must be empty. | |
1082 | */ | |
528f664c SL |
1083 | rename() |
1084 | { | |
1085 | struct a { | |
1086 | char *from; | |
1087 | char *to; | |
715baff1 | 1088 | } *uap = (struct a *)u.u_ap; |
fc2aed1e | 1089 | register struct vnode *tvp, *fvp, *tdvp; |
715baff1 | 1090 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
1091 | struct nameidata tond; |
1092 | int error; | |
4f083fd7 | 1093 | |
fc2aed1e | 1094 | ndp->ni_nameiop = DELETE | WANTPARENT; |
715baff1 KM |
1095 | ndp->ni_segflg = UIO_USERSPACE; |
1096 | ndp->ni_dirp = uap->from; | |
fc2aed1e KM |
1097 | if (error = namei(ndp)) |
1098 | RETURN (error); | |
1099 | fvp = ndp->ni_vp; | |
41eb2f3d | 1100 | nddup(ndp, &tond); |
fc2aed1e KM |
1101 | tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; |
1102 | tond.ni_segflg = UIO_USERSPACE; | |
1103 | tond.ni_dirp = uap->to; | |
fc2aed1e KM |
1104 | error = namei(&tond); |
1105 | tdvp = tond.ni_dvp; | |
1106 | tvp = tond.ni_vp; | |
1107 | if (tvp != NULL) { | |
1108 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { | |
a5390dce | 1109 | error = EISDIR; |
fc2aed1e KM |
1110 | goto out; |
1111 | } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { | |
1112 | error = ENOTDIR; | |
1113 | goto out; | |
a5390dce | 1114 | } |
4f083fd7 | 1115 | } |
fc2aed1e KM |
1116 | if (error) { |
1117 | VOP_ABORTOP(ndp); | |
1118 | goto out1; | |
4f083fd7 | 1119 | } |
fc2aed1e KM |
1120 | if (fvp->v_mount != tdvp->v_mount) { |
1121 | error = EXDEV; | |
1122 | goto out; | |
64d3a787 | 1123 | } |
fc2aed1e KM |
1124 | if (fvp == tdvp || fvp == tvp) |
1125 | error = EINVAL; | |
1126 | out: | |
1127 | if (error) { | |
1128 | VOP_ABORTOP(&tond); | |
1129 | VOP_ABORTOP(ndp); | |
1130 | } else { | |
1131 | error = VOP_RENAME(ndp, &tond); | |
64d3a787 | 1132 | } |
fc2aed1e | 1133 | out1: |
41eb2f3d | 1134 | ndrele(&tond); |
fc2aed1e | 1135 | RETURN (error); |
64d3a787 | 1136 | } |
88a7a62a | 1137 | |
88a7a62a SL |
1138 | /* |
1139 | * Mkdir system call | |
1140 | */ | |
1141 | mkdir() | |
1142 | { | |
1143 | struct a { | |
1144 | char *name; | |
1145 | int dmode; | |
715baff1 | 1146 | } *uap = (struct a *)u.u_ap; |
715baff1 | 1147 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
1148 | register struct vnode *vp; |
1149 | struct vattr vattr; | |
1150 | int error; | |
88a7a62a | 1151 | |
fc2aed1e | 1152 | ndp->ni_nameiop = CREATE | LOCKPARENT; |
715baff1 KM |
1153 | ndp->ni_segflg = UIO_USERSPACE; |
1154 | ndp->ni_dirp = uap->name; | |
fc2aed1e KM |
1155 | if (error = namei(ndp)) |
1156 | RETURN (error); | |
1157 | vp = ndp->ni_vp; | |
1158 | if (vp != NULL) { | |
1159 | VOP_ABORTOP(ndp); | |
1160 | RETURN (EEXIST); | |
88a7a62a | 1161 | } |
fc2aed1e KM |
1162 | vattr_null(&vattr); |
1163 | vattr.va_type = VDIR; | |
1164 | vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; | |
1165 | error = VOP_MKDIR(ndp, &vattr); | |
5dfd04f0 KM |
1166 | if (!error) |
1167 | vput(ndp->ni_vp); | |
fc2aed1e | 1168 | RETURN (error); |
88a7a62a SL |
1169 | } |
1170 | ||
1171 | /* | |
1172 | * Rmdir system call. | |
1173 | */ | |
1174 | rmdir() | |
1175 | { | |
1176 | struct a { | |
1177 | char *name; | |
715baff1 | 1178 | } *uap = (struct a *)u.u_ap; |
715baff1 | 1179 | register struct nameidata *ndp = &u.u_nd; |
fc2aed1e KM |
1180 | register struct vnode *vp; |
1181 | int error; | |
88a7a62a | 1182 | |
fc2aed1e | 1183 | ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; |
715baff1 KM |
1184 | ndp->ni_segflg = UIO_USERSPACE; |
1185 | ndp->ni_dirp = uap->name; | |
fc2aed1e KM |
1186 | if (error = namei(ndp)) |
1187 | RETURN (error); | |
1188 | vp = ndp->ni_vp; | |
1189 | if (vp->v_type != VDIR) { | |
1190 | error = ENOTDIR; | |
88a7a62a SL |
1191 | goto out; |
1192 | } | |
1193 | /* | |
fc2aed1e | 1194 | * No rmdir "." please. |
88a7a62a | 1195 | */ |
fc2aed1e KM |
1196 | if (ndp->ni_dvp == vp) { |
1197 | error = EINVAL; | |
88a7a62a SL |
1198 | goto out; |
1199 | } | |
1200 | /* | |
fc2aed1e | 1201 | * Don't unlink a mounted file. |
88a7a62a | 1202 | */ |
fc2aed1e KM |
1203 | if (vp->v_flag & VROOT) |
1204 | error = EBUSY; | |
88a7a62a | 1205 | out: |
fc2aed1e KM |
1206 | if (error) |
1207 | VOP_ABORTOP(ndp); | |
1208 | else | |
1209 | error = VOP_RMDIR(ndp); | |
1210 | RETURN (error); | |
88a7a62a SL |
1211 | } |
1212 | ||
fc2aed1e KM |
1213 | /* |
1214 | * Read a block of directory entries in a file system independent format | |
1215 | */ | |
1216 | getdirentries() | |
88a7a62a | 1217 | { |
fc2aed1e KM |
1218 | register struct a { |
1219 | int fd; | |
1220 | char *buf; | |
1221 | unsigned count; | |
1222 | long *basep; | |
1223 | } *uap = (struct a *)u.u_ap; | |
8462a185 | 1224 | struct file *fp; |
fc2aed1e KM |
1225 | struct uio auio; |
1226 | struct iovec aiov; | |
58030ad2 | 1227 | off_t off; |
fc2aed1e KM |
1228 | int error; |
1229 | ||
1230 | if (error = getvnode(uap->fd, &fp)) | |
1231 | RETURN (error); | |
1232 | if ((fp->f_flag & FREAD) == 0) | |
1233 | RETURN (EBADF); | |
1234 | aiov.iov_base = uap->buf; | |
1235 | aiov.iov_len = uap->count; | |
1236 | auio.uio_iov = &aiov; | |
1237 | auio.uio_iovcnt = 1; | |
1238 | auio.uio_rw = UIO_READ; | |
1239 | auio.uio_segflg = UIO_USERSPACE; | |
1240 | auio.uio_resid = uap->count; | |
58030ad2 | 1241 | off = fp->f_offset; |
fc2aed1e KM |
1242 | if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, |
1243 | &(fp->f_offset), fp->f_cred)) | |
1244 | RETURN (error); | |
58030ad2 | 1245 | error = copyout((caddr_t)&off, (caddr_t)uap->basep, |
fc2aed1e KM |
1246 | sizeof(long)); |
1247 | u.u_r.r_val1 = uap->count - auio.uio_resid; | |
1248 | RETURN (error); | |
88a7a62a SL |
1249 | } |
1250 | ||
1251 | /* | |
1252 | * mode mask for creation of files | |
1253 | */ | |
1254 | umask() | |
1255 | { | |
1256 | register struct a { | |
1257 | int mask; | |
715baff1 | 1258 | } *uap = (struct a *)u.u_ap; |
88a7a62a | 1259 | |
88a7a62a SL |
1260 | u.u_r.r_val1 = u.u_cmask; |
1261 | u.u_cmask = uap->mask & 07777; | |
fc2aed1e KM |
1262 | RETURN (0); |
1263 | } | |
1264 | ||
1265 | getvnode(fdes, fpp) | |
1266 | struct file **fpp; | |
1267 | int fdes; | |
1268 | { | |
1269 | struct file *fp; | |
1270 | ||
1271 | if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) | |
1272 | return (EBADF); | |
1273 | if (fp->f_type != DTYPE_VNODE) | |
1274 | return (EINVAL); | |
1275 | *fpp = fp; | |
1276 | return (0); | |
88a7a62a | 1277 | } |