scoutos / prex-0.9.0 / usr / server / fs / vfs / vfs_syscalls.c @ 03e9c04a
History | View | Annotate | Download (13.8 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2005-2007, Kohsuke Ohtani
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions
|
7 |
* are met:
|
8 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
/*
|
31 |
* vfs_syscalls.c - everything in this file is a routine implementing
|
32 |
* a VFS system call.
|
33 |
*/
|
34 |
|
35 |
#include <sys/prex.h> |
36 |
#include <sys/stat.h> |
37 |
#include <sys/vnode.h> |
38 |
#include <sys/file.h> |
39 |
#include <sys/mount.h> |
40 |
#include <sys/dirent.h> |
41 |
#include <sys/list.h> |
42 |
#include <sys/buf.h> |
43 |
|
44 |
#include <limits.h> |
45 |
#include <unistd.h> |
46 |
#include <stdlib.h> |
47 |
#include <string.h> |
48 |
#include <stdio.h> |
49 |
#include <errno.h> |
50 |
#include <fcntl.h> |
51 |
|
52 |
#include "vfs.h" |
53 |
|
54 |
int
|
55 |
sys_open(char *path, int flags, mode_t mode, file_t *pfp) |
56 |
{ |
57 |
vnode_t vp, dvp; |
58 |
file_t fp; |
59 |
char *filename;
|
60 |
int error;
|
61 |
|
62 |
DPRINTF(VFSDB_SYSCALL, ("sys_open: path=%s flags=%x mode=%x\n",
|
63 |
path, flags, mode)); |
64 |
|
65 |
flags = FFLAGS(flags); |
66 |
if ((flags & (FREAD | FWRITE)) == 0) |
67 |
return EINVAL;
|
68 |
if (flags & O_CREAT) {
|
69 |
error = namei(path, &vp); |
70 |
if (error == ENOENT) {
|
71 |
/* Create new file. */
|
72 |
if ((error = lookup(path, &dvp, &filename)) != 0) |
73 |
return error;
|
74 |
if ((error = vn_access(dvp, VWRITE)) != 0) { |
75 |
vput(dvp); |
76 |
return error;
|
77 |
} |
78 |
mode &= ~S_IFMT; |
79 |
mode |= S_IFREG; |
80 |
error = VOP_CREATE(dvp, filename, mode); |
81 |
vput(dvp); |
82 |
if (error)
|
83 |
return error;
|
84 |
if ((error = namei(path, &vp)) != 0) |
85 |
return error;
|
86 |
flags &= ~O_TRUNC; |
87 |
} else if (error) { |
88 |
return error;
|
89 |
} else {
|
90 |
/* File already exits */
|
91 |
if (flags & O_EXCL) {
|
92 |
vput(vp); |
93 |
return EEXIST;
|
94 |
} |
95 |
flags &= ~O_CREAT; |
96 |
} |
97 |
} else {
|
98 |
/* Open */
|
99 |
if ((error = namei(path, &vp)) != 0) |
100 |
return error;
|
101 |
} |
102 |
if ((flags & O_CREAT) == 0) { |
103 |
if (flags & FWRITE || flags & O_TRUNC) {
|
104 |
if ((error = vn_access(vp, VWRITE)) != 0) { |
105 |
vput(vp); |
106 |
return error;
|
107 |
} |
108 |
if (vp->v_type == VDIR) {
|
109 |
/* Openning directory with writable. */
|
110 |
vput(vp); |
111 |
return EISDIR;
|
112 |
} |
113 |
} |
114 |
} |
115 |
/* Process truncate request */
|
116 |
if (flags & O_TRUNC) {
|
117 |
if (!(flags & FWRITE) || (vp->v_type == VDIR)) {
|
118 |
vput(vp); |
119 |
return EINVAL;
|
120 |
} |
121 |
if ((error = VOP_TRUNCATE(vp, 0)) != 0) { |
122 |
vput(vp); |
123 |
return error;
|
124 |
} |
125 |
} |
126 |
/* Setup file structure */
|
127 |
if (!(fp = malloc(sizeof(struct file)))) { |
128 |
vput(vp); |
129 |
return ENOMEM;
|
130 |
} |
131 |
/* Request to file system */
|
132 |
if ((error = VOP_OPEN(vp, flags)) != 0) { |
133 |
free(fp); |
134 |
vput(vp); |
135 |
return error;
|
136 |
} |
137 |
memset(fp, 0, sizeof(struct file)); |
138 |
fp->f_vnode = vp; |
139 |
fp->f_flags = flags; |
140 |
fp->f_offset = 0;
|
141 |
fp->f_count = 1;
|
142 |
*pfp = fp; |
143 |
vn_unlock(vp); |
144 |
return 0; |
145 |
} |
146 |
|
147 |
int
|
148 |
sys_close(file_t fp) |
149 |
{ |
150 |
vnode_t vp; |
151 |
int error;
|
152 |
|
153 |
DPRINTF(VFSDB_SYSCALL, ("sys_close: fp=%x count=%d\n",
|
154 |
(u_int)fp, fp->f_count)); |
155 |
|
156 |
if (fp->f_count <= 0) |
157 |
sys_panic("sys_close");
|
158 |
|
159 |
vp = fp->f_vnode; |
160 |
if (--fp->f_count > 0) { |
161 |
vrele(vp); |
162 |
return 0; |
163 |
} |
164 |
vn_lock(vp); |
165 |
if ((error = VOP_CLOSE(vp, fp)) != 0) { |
166 |
vn_unlock(vp); |
167 |
return error;
|
168 |
} |
169 |
vput(vp); |
170 |
free(fp); |
171 |
return 0; |
172 |
} |
173 |
|
174 |
int
|
175 |
sys_read(file_t fp, void *buf, size_t size, size_t *count)
|
176 |
{ |
177 |
vnode_t vp; |
178 |
int error;
|
179 |
|
180 |
DPRINTF(VFSDB_SYSCALL, ("sys_read: fp=%x buf=%x size=%d\n",
|
181 |
(u_int)fp, (u_int)buf, size)); |
182 |
|
183 |
if ((fp->f_flags & FREAD) == 0) |
184 |
return EBADF;
|
185 |
if (size == 0) { |
186 |
*count = 0;
|
187 |
return 0; |
188 |
} |
189 |
vp = fp->f_vnode; |
190 |
vn_lock(vp); |
191 |
error = VOP_READ(vp, fp, buf, size, count); |
192 |
vn_unlock(vp); |
193 |
return error;
|
194 |
} |
195 |
|
196 |
int
|
197 |
sys_write(file_t fp, void *buf, size_t size, size_t *count)
|
198 |
{ |
199 |
vnode_t vp; |
200 |
int error;
|
201 |
|
202 |
DPRINTF(VFSDB_SYSCALL, ("sys_write: fp=%x buf=%x size=%d\n",
|
203 |
(u_int)fp, (u_int)buf, size)); |
204 |
|
205 |
if ((fp->f_flags & FWRITE) == 0) |
206 |
return EBADF;
|
207 |
if (size == 0) { |
208 |
*count = 0;
|
209 |
return 0; |
210 |
} |
211 |
vp = fp->f_vnode; |
212 |
vn_lock(vp); |
213 |
error = VOP_WRITE(vp, fp, buf, size, count); |
214 |
vn_unlock(vp); |
215 |
return error;
|
216 |
} |
217 |
|
218 |
int
|
219 |
sys_lseek(file_t fp, off_t off, int type, off_t *origin)
|
220 |
{ |
221 |
vnode_t vp; |
222 |
|
223 |
DPRINTF(VFSDB_SYSCALL, ("sys_seek: fp=%x off=%d type=%d\n",
|
224 |
(u_int)fp, (u_int)off, type)); |
225 |
|
226 |
vp = fp->f_vnode; |
227 |
vn_lock(vp); |
228 |
switch (type) {
|
229 |
case SEEK_SET:
|
230 |
if (off < 0) |
231 |
off = 0;
|
232 |
if (off > (off_t)vp->v_size)
|
233 |
off = vp->v_size; |
234 |
break;
|
235 |
case SEEK_CUR:
|
236 |
if (fp->f_offset + off > (off_t)vp->v_size)
|
237 |
off = vp->v_size; |
238 |
else if (fp->f_offset + off < 0) |
239 |
off = 0;
|
240 |
else
|
241 |
off = fp->f_offset + off; |
242 |
break;
|
243 |
case SEEK_END:
|
244 |
if (off > 0) |
245 |
off = vp->v_size; |
246 |
else if ((int)vp->v_size + off < 0) |
247 |
off = 0;
|
248 |
else
|
249 |
off = vp->v_size + off; |
250 |
break;
|
251 |
default:
|
252 |
vn_unlock(vp); |
253 |
return EINVAL;
|
254 |
} |
255 |
/* Request to check the file offset */
|
256 |
if (VOP_SEEK(vp, fp, fp->f_offset, off) != 0) { |
257 |
vn_unlock(vp); |
258 |
return EINVAL;
|
259 |
} |
260 |
*origin = off; |
261 |
fp->f_offset = off; |
262 |
vn_unlock(vp); |
263 |
return 0; |
264 |
} |
265 |
|
266 |
int
|
267 |
sys_ioctl(file_t fp, u_long request, void *buf)
|
268 |
{ |
269 |
vnode_t vp; |
270 |
int error;
|
271 |
|
272 |
DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: fp=%x request=%x\n", fp, request));
|
273 |
|
274 |
if ((fp->f_flags & (FREAD | FWRITE)) == 0) |
275 |
return EBADF;
|
276 |
|
277 |
vp = fp->f_vnode; |
278 |
vn_lock(vp); |
279 |
error = VOP_IOCTL(vp, fp, request, buf); |
280 |
vn_unlock(vp); |
281 |
DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: comp error=%d\n", error));
|
282 |
return error;
|
283 |
} |
284 |
|
285 |
int
|
286 |
sys_fsync(file_t fp) |
287 |
{ |
288 |
vnode_t vp; |
289 |
int error;
|
290 |
|
291 |
DPRINTF(VFSDB_SYSCALL, ("sys_fsync: fp=%x\n", fp));
|
292 |
|
293 |
if ((fp->f_flags & FWRITE) == 0) |
294 |
return EBADF;
|
295 |
|
296 |
vp = fp->f_vnode; |
297 |
vn_lock(vp); |
298 |
error = VOP_FSYNC(vp, fp); |
299 |
vn_unlock(vp); |
300 |
return error;
|
301 |
} |
302 |
|
303 |
int
|
304 |
sys_fstat(file_t fp, struct stat *st)
|
305 |
{ |
306 |
vnode_t vp; |
307 |
int error = 0; |
308 |
|
309 |
DPRINTF(VFSDB_SYSCALL, ("sys_fstat: fp=%x\n", fp));
|
310 |
|
311 |
vp = fp->f_vnode; |
312 |
vn_lock(vp); |
313 |
error = vn_stat(vp, st); |
314 |
vn_unlock(vp); |
315 |
return error;
|
316 |
} |
317 |
|
318 |
/*
|
319 |
* Return 0 if directory is empty
|
320 |
*/
|
321 |
static int |
322 |
check_dir_empty(char *path)
|
323 |
{ |
324 |
int error;
|
325 |
file_t fp; |
326 |
struct dirent dir;
|
327 |
|
328 |
DPRINTF(VFSDB_SYSCALL, ("check_dir_empty\n"));
|
329 |
|
330 |
if ((error = sys_opendir(path, &fp)) != 0) |
331 |
return error;
|
332 |
do {
|
333 |
error = sys_readdir(fp, &dir); |
334 |
if (error != 0 && error != EACCES) |
335 |
break;
|
336 |
} while (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, "..")); |
337 |
|
338 |
sys_closedir(fp); |
339 |
|
340 |
if (error == ENOENT)
|
341 |
return 0; |
342 |
else if (error == 0) |
343 |
return EEXIST;
|
344 |
return error;
|
345 |
} |
346 |
|
347 |
int
|
348 |
sys_opendir(char *path, file_t *file)
|
349 |
{ |
350 |
vnode_t dvp; |
351 |
file_t fp; |
352 |
int error;
|
353 |
|
354 |
DPRINTF(VFSDB_SYSCALL, ("sys_opendir: path=%s\n", path));
|
355 |
|
356 |
if ((error = sys_open(path, O_RDONLY, 0, &fp)) != 0) |
357 |
return error;
|
358 |
|
359 |
dvp = fp->f_vnode; |
360 |
vn_lock(dvp); |
361 |
if (dvp->v_type != VDIR) {
|
362 |
vn_unlock(dvp); |
363 |
sys_close(fp); |
364 |
return ENOTDIR;
|
365 |
} |
366 |
vn_unlock(dvp); |
367 |
|
368 |
*file = fp; |
369 |
return 0; |
370 |
} |
371 |
|
372 |
int
|
373 |
sys_closedir(file_t fp) |
374 |
{ |
375 |
vnode_t dvp; |
376 |
int error;
|
377 |
|
378 |
DPRINTF(VFSDB_SYSCALL, ("sys_closedir: fp=%x\n", fp));
|
379 |
|
380 |
dvp = fp->f_vnode; |
381 |
vn_lock(dvp); |
382 |
if (dvp->v_type != VDIR) {
|
383 |
vn_unlock(dvp); |
384 |
return EBADF;
|
385 |
} |
386 |
vn_unlock(dvp); |
387 |
error = sys_close(fp); |
388 |
return error;
|
389 |
} |
390 |
|
391 |
int
|
392 |
sys_readdir(file_t fp, struct dirent *dir)
|
393 |
{ |
394 |
vnode_t dvp; |
395 |
int error;
|
396 |
|
397 |
DPRINTF(VFSDB_SYSCALL, ("sys_readdir: fp=%x\n", fp));
|
398 |
|
399 |
dvp = fp->f_vnode; |
400 |
vn_lock(dvp); |
401 |
if (dvp->v_type != VDIR) {
|
402 |
vn_unlock(dvp); |
403 |
return EBADF;
|
404 |
} |
405 |
error = VOP_READDIR(dvp, fp, dir); |
406 |
DPRINTF(VFSDB_SYSCALL, ("sys_readdir: error=%d path=%s\n",
|
407 |
error, dir->d_name)); |
408 |
vn_unlock(dvp); |
409 |
return error;
|
410 |
} |
411 |
|
412 |
int
|
413 |
sys_rewinddir(file_t fp) |
414 |
{ |
415 |
vnode_t dvp; |
416 |
|
417 |
dvp = fp->f_vnode; |
418 |
vn_lock(dvp); |
419 |
if (dvp->v_type != VDIR) {
|
420 |
vn_unlock(dvp); |
421 |
return EBADF;
|
422 |
} |
423 |
fp->f_offset = 0;
|
424 |
vn_unlock(dvp); |
425 |
return 0; |
426 |
} |
427 |
|
428 |
int
|
429 |
sys_seekdir(file_t fp, long loc)
|
430 |
{ |
431 |
vnode_t dvp; |
432 |
|
433 |
dvp = fp->f_vnode; |
434 |
vn_lock(dvp); |
435 |
if (dvp->v_type != VDIR) {
|
436 |
vn_unlock(dvp); |
437 |
return EBADF;
|
438 |
} |
439 |
fp->f_offset = (off_t)loc; |
440 |
vn_unlock(dvp); |
441 |
return 0; |
442 |
} |
443 |
|
444 |
int
|
445 |
sys_telldir(file_t fp, long *loc)
|
446 |
{ |
447 |
vnode_t dvp; |
448 |
|
449 |
dvp = fp->f_vnode; |
450 |
vn_lock(dvp); |
451 |
if (dvp->v_type != VDIR) {
|
452 |
vn_unlock(dvp); |
453 |
return EBADF;
|
454 |
} |
455 |
*loc = (long)fp->f_offset;
|
456 |
vn_unlock(dvp); |
457 |
return 0; |
458 |
} |
459 |
|
460 |
int
|
461 |
sys_mkdir(char *path, mode_t mode)
|
462 |
{ |
463 |
char *name;
|
464 |
vnode_t vp, dvp; |
465 |
int error;
|
466 |
|
467 |
DPRINTF(VFSDB_SYSCALL, ("sys_mkdir: path=%s mode=%d\n", path, mode));
|
468 |
|
469 |
if ((error = namei(path, &vp)) == 0) { |
470 |
/* File already exists */
|
471 |
vput(vp); |
472 |
return EEXIST;
|
473 |
} |
474 |
/* Notice: vp is invalid here! */
|
475 |
|
476 |
if ((error = lookup(path, &dvp, &name)) != 0) { |
477 |
/* Directory already exists */
|
478 |
return error;
|
479 |
} |
480 |
if ((error = vn_access(dvp, VWRITE)) != 0) |
481 |
goto out;
|
482 |
mode &= ~S_IFMT; |
483 |
mode |= S_IFDIR; |
484 |
|
485 |
error = VOP_MKDIR(dvp, name, mode); |
486 |
out:
|
487 |
vput(dvp); |
488 |
return error;
|
489 |
} |
490 |
|
491 |
int
|
492 |
sys_rmdir(char *path)
|
493 |
{ |
494 |
vnode_t vp, dvp; |
495 |
int error;
|
496 |
char *name;
|
497 |
|
498 |
DPRINTF(VFSDB_SYSCALL, ("sys_rmdir: path=%s\n", path));
|
499 |
|
500 |
if ((error = check_dir_empty(path)) != 0) |
501 |
return error;
|
502 |
if ((error = namei(path, &vp)) != 0) |
503 |
return error;
|
504 |
if ((error = vn_access(vp, VWRITE)) != 0) |
505 |
goto out;
|
506 |
if (vp->v_type != VDIR) {
|
507 |
error = ENOTDIR; |
508 |
goto out;
|
509 |
} |
510 |
if (vp->v_flags & VROOT || vcount(vp) >= 2) { |
511 |
error = EBUSY; |
512 |
goto out;
|
513 |
} |
514 |
if ((error = lookup(path, &dvp, &name)) != 0) |
515 |
goto out;
|
516 |
|
517 |
error = VOP_RMDIR(dvp, vp, name); |
518 |
vn_unlock(vp); |
519 |
vgone(vp); |
520 |
vput(dvp); |
521 |
return error;
|
522 |
|
523 |
out:
|
524 |
vput(vp); |
525 |
return error;
|
526 |
} |
527 |
|
528 |
int
|
529 |
sys_mknod(char *path, mode_t mode)
|
530 |
{ |
531 |
char *name;
|
532 |
vnode_t vp, dvp; |
533 |
int error;
|
534 |
|
535 |
DPRINTF(VFSDB_SYSCALL, ("sys_mknod: path=%s mode=%d\n", path, mode));
|
536 |
|
537 |
switch (mode & S_IFMT) {
|
538 |
case S_IFREG:
|
539 |
case S_IFDIR:
|
540 |
case S_IFIFO:
|
541 |
case S_IFSOCK:
|
542 |
/* OK */
|
543 |
break;
|
544 |
default:
|
545 |
return EINVAL;
|
546 |
} |
547 |
|
548 |
if ((error = namei(path, &vp)) == 0) { |
549 |
vput(vp); |
550 |
return EEXIST;
|
551 |
} |
552 |
|
553 |
if ((error = lookup(path, &dvp, &name)) != 0) |
554 |
return error;
|
555 |
if ((error = vn_access(dvp, VWRITE)) != 0) |
556 |
goto out;
|
557 |
if (S_ISDIR(mode))
|
558 |
error = VOP_MKDIR(dvp, name, mode); |
559 |
else
|
560 |
error = VOP_CREATE(dvp, name, mode); |
561 |
out:
|
562 |
vput(dvp); |
563 |
return error;
|
564 |
} |
565 |
|
566 |
int
|
567 |
sys_rename(char *src, char *dest) |
568 |
{ |
569 |
vnode_t vp1, vp2 = 0, dvp1, dvp2;
|
570 |
char *sname, *dname;
|
571 |
int error;
|
572 |
size_t len; |
573 |
char root[] = "/"; |
574 |
|
575 |
DPRINTF(VFSDB_SYSCALL, ("sys_rename: src=%s dest=%s\n", src, dest));
|
576 |
|
577 |
if ((error = namei(src, &vp1)) != 0) |
578 |
return error;
|
579 |
if ((error = vn_access(vp1, VWRITE)) != 0) |
580 |
goto err1;
|
581 |
|
582 |
/* If source and dest are the same, do nothing */
|
583 |
if (!strncmp(src, dest, PATH_MAX))
|
584 |
goto err1;
|
585 |
|
586 |
/* Check if target is directory of source */
|
587 |
len = strlen(dest); |
588 |
if (!strncmp(src, dest, len)) {
|
589 |
error = EINVAL; |
590 |
goto err1;
|
591 |
} |
592 |
/* Is the source busy ? */
|
593 |
if (vcount(vp1) >= 2) { |
594 |
error = EBUSY; |
595 |
goto err1;
|
596 |
} |
597 |
/* Check type of source & target */
|
598 |
error = namei(dest, &vp2); |
599 |
if (error == 0) { |
600 |
/* target exists */
|
601 |
if (vp1->v_type == VDIR && vp2->v_type != VDIR) {
|
602 |
error = ENOTDIR; |
603 |
goto err2;
|
604 |
} else if (vp1->v_type != VDIR && vp2->v_type == VDIR) { |
605 |
error = EISDIR; |
606 |
goto err2;
|
607 |
} |
608 |
if (vp2->v_type == VDIR && check_dir_empty(dest)) {
|
609 |
error = EEXIST; |
610 |
goto err2;
|
611 |
} |
612 |
|
613 |
if (vcount(vp2) >= 2) { |
614 |
error = EBUSY; |
615 |
goto err2;
|
616 |
} |
617 |
} |
618 |
|
619 |
dname = strrchr(dest, '/');
|
620 |
if (dname == NULL) { |
621 |
error = ENOTDIR; |
622 |
goto err2;
|
623 |
} |
624 |
if (dname == dest)
|
625 |
dest = root; |
626 |
|
627 |
*dname = 0;
|
628 |
dname++; |
629 |
|
630 |
if ((error = lookup(src, &dvp1, &sname)) != 0) |
631 |
goto err2;
|
632 |
|
633 |
if ((error = namei(dest, &dvp2)) != 0) |
634 |
goto err3;
|
635 |
|
636 |
/* The source and dest must be same file system */
|
637 |
if (dvp1->v_mount != dvp2->v_mount) {
|
638 |
error = EXDEV; |
639 |
goto err4;
|
640 |
} |
641 |
error = VOP_RENAME(dvp1, vp1, sname, dvp2, vp2, dname); |
642 |
err4:
|
643 |
vput(dvp2); |
644 |
err3:
|
645 |
vput(dvp1); |
646 |
err2:
|
647 |
if (vp2)
|
648 |
vput(vp2); |
649 |
err1:
|
650 |
vput(vp1); |
651 |
return error;
|
652 |
} |
653 |
|
654 |
int
|
655 |
sys_unlink(char *path)
|
656 |
{ |
657 |
char *name;
|
658 |
vnode_t vp, dvp; |
659 |
int error;
|
660 |
|
661 |
DPRINTF(VFSDB_SYSCALL, ("sys_unlink: path=%s\n", path));
|
662 |
|
663 |
if ((error = namei(path, &vp)) != 0) |
664 |
return error;
|
665 |
if ((error = vn_access(vp, VWRITE)) != 0) |
666 |
goto out;
|
667 |
if (vp->v_type == VDIR) {
|
668 |
error = EPERM; |
669 |
goto out;
|
670 |
} |
671 |
/* XXX: Need to allow unlink for opened file. */
|
672 |
if (vp->v_flags & VROOT || vcount(vp) >= 2) { |
673 |
error = EBUSY; |
674 |
goto out;
|
675 |
} |
676 |
if ((error = lookup(path, &dvp, &name)) != 0) |
677 |
goto out;
|
678 |
|
679 |
error = VOP_REMOVE(dvp, vp, name); |
680 |
|
681 |
vn_unlock(vp); |
682 |
vgone(vp); |
683 |
vput(dvp); |
684 |
return 0; |
685 |
out:
|
686 |
vput(vp); |
687 |
return error;
|
688 |
} |
689 |
|
690 |
int
|
691 |
sys_access(char *path, int mode) |
692 |
{ |
693 |
vnode_t vp; |
694 |
int error, flags;
|
695 |
|
696 |
DPRINTF(VFSDB_SYSCALL, ("sys_access: path=%s mode=%x\n", path, mode));
|
697 |
|
698 |
/* If F_OK is set, we return here if file is not found. */
|
699 |
if ((error = namei(path, &vp)) != 0) |
700 |
return error;
|
701 |
|
702 |
flags = 0;
|
703 |
if (mode & R_OK)
|
704 |
flags |= VREAD; |
705 |
if (mode & W_OK)
|
706 |
flags |= VWRITE; |
707 |
if (mode & X_OK)
|
708 |
flags |= VEXEC; |
709 |
|
710 |
error = vn_access(vp, flags); |
711 |
|
712 |
vput(vp); |
713 |
return error;
|
714 |
} |
715 |
|
716 |
int
|
717 |
sys_stat(char *path, struct stat *st) |
718 |
{ |
719 |
vnode_t vp; |
720 |
int error;
|
721 |
|
722 |
DPRINTF(VFSDB_SYSCALL, ("sys_stat: path=%s\n", path));
|
723 |
|
724 |
if ((error = namei(path, &vp)) != 0) |
725 |
return error;
|
726 |
error = vn_stat(vp, st); |
727 |
vput(vp); |
728 |
return error;
|
729 |
} |
730 |
|
731 |
int
|
732 |
sys_truncate(char *path, off_t length)
|
733 |
{ |
734 |
return 0; |
735 |
} |
736 |
|
737 |
int
|
738 |
sys_ftruncate(file_t fp, off_t length) |
739 |
{ |
740 |
return 0; |
741 |
} |
742 |
|
743 |
int
|
744 |
sys_fchdir(file_t fp, char *cwd)
|
745 |
{ |
746 |
vnode_t dvp; |
747 |
|
748 |
dvp = fp->f_vnode; |
749 |
vn_lock(dvp); |
750 |
if (dvp->v_type != VDIR) {
|
751 |
vn_unlock(dvp); |
752 |
return EBADF;
|
753 |
} |
754 |
strlcpy(cwd, dvp->v_path, PATH_MAX); |
755 |
vn_unlock(dvp); |
756 |
return 0; |
757 |
} |