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