Annotation of src/sys/fs/v7fs/v7fs_vnops.c, Revision 1.11.2.3
1.11.2.1 tls 1: /* $NetBSD$ */
1.1 uch 2:
3: /*-
4: * Copyright (c) 2004, 2011 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by UCHIYAMA Yasushi.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: #include <sys/cdefs.h>
1.11.2.1 tls 33: __KERNEL_RCSID(0, "$NetBSD$");
1.1 uch 34: #if defined _KERNEL_OPT
35: #include "opt_v7fs.h"
36: #endif
37:
38: #include <sys/param.h>
39: #include <sys/kernel.h>
40: #include <sys/resource.h>
41: #include <sys/vnode.h>
42: #include <sys/namei.h>
43: #include <sys/dirent.h>
1.11.2.2 tls 44: #include <sys/kmem.h>
1.1 uch 45: #include <sys/lockf.h>
46: #include <sys/unistd.h>
47: #include <sys/fcntl.h>
48: #include <sys/kauth.h>
49: #include <sys/buf.h>
50: #include <sys/stat.h> /*APPEND */
51: #include <miscfs/genfs/genfs.h>
52:
53: #include <fs/v7fs/v7fs.h>
54: #include <fs/v7fs/v7fs_impl.h>
55: #include <fs/v7fs/v7fs_inode.h>
56: #include <fs/v7fs/v7fs_dirent.h>
57: #include <fs/v7fs/v7fs_file.h>
58: #include <fs/v7fs/v7fs_datablock.h>
59: #include <fs/v7fs/v7fs_extern.h>
60:
61: #ifdef V7FS_VNOPS_DEBUG
62: #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
63: #else
64: #define DPRINTF(arg...) ((void)0)
65: #endif
66:
67: static v7fs_mode_t vtype_to_v7fs_mode(enum vtype);
68: static uint8_t v7fs_mode_to_d_type(v7fs_mode_t);
69:
70: static v7fs_mode_t
71: vtype_to_v7fs_mode(enum vtype type)
72: {
73: /* Convert Vnode types to V7FS types (sys/vnode.h)*/
74: v7fs_mode_t table[] = { 0, V7FS_IFREG, V7FS_IFDIR, V7FS_IFBLK,
75: V7FS_IFCHR, V7FSBSD_IFLNK, V7FSBSD_IFSOCK,
76: V7FSBSD_IFFIFO };
77: return table[type];
78: }
79:
80: static uint8_t
81: v7fs_mode_to_d_type(v7fs_mode_t mode)
82: {
83: /* Convert V7FS types to dirent d_type (sys/dirent.h)*/
84:
85: return (mode & V7FS_IFMT) >> 12;
86: }
87:
88: int
89: v7fs_lookup(void *v)
90: {
1.11.2.2 tls 91: struct vop_lookup_v2_args /* {
1.1 uch 92: struct vnode *a_dvp;
93: struct vnode **a_vpp;
94: struct componentname *a_cnp;
95: } */ *a = v;
96: struct vnode *dvp = a->a_dvp;
97: struct v7fs_node *parent_node = dvp->v_data;
98: struct v7fs_inode *parent = &parent_node->inode;
99: struct v7fs_self *fs = parent_node->v7fsmount->core;/* my filesystem */
100: struct vnode *vpp;
101: struct componentname *cnp = a->a_cnp;
102: int nameiop = cnp->cn_nameiop;
103: const char *name = cnp->cn_nameptr;
104: int namelen = cnp->cn_namelen;
105: int flags = cnp->cn_flags;
106: bool isdotdot = flags & ISDOTDOT;
107: bool islastcn = flags & ISLASTCN;
108: v7fs_ino_t ino;
109: int error;
1.6 uch 110: #ifdef V7FS_VNOPS_DEBUG
111: const char *opname[] = { "LOOKUP", "CREATE", "DELETE", "RENAME" };
112: #endif
113: DPRINTF("'%s' op=%s flags=%d parent=%d %o %dbyte\n", name,
114: opname[nameiop], cnp->cn_flags, parent->inode_number, parent->mode,
1.1 uch 115: parent->filesize);
116:
117: *a->a_vpp = 0;
118:
119: /* Check directory permission for search */
120: if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred))) {
121: DPRINTF("***perm.\n");
122: return error;
123: }
124:
125: /* Deny last component write operation on a read-only mount */
126: if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
127: (nameiop == DELETE || nameiop == RENAME)) {
128: DPRINTF("***ROFS.\n");
129: return EROFS;
130: }
131:
1.11.2.3! jdolecek 132: /* No lookup on removed directory */
! 133: if (v7fs_inode_nlink(parent) == 0)
! 134: return ENOENT;
! 135:
1.1 uch 136: /* "." */
137: if (namelen == 1 && name[0] == '.') {
1.6 uch 138: if ((nameiop == RENAME) && islastcn) {
139: return EISDIR; /* t_vnops rename_dir(3) */
140: }
1.1 uch 141: vref(dvp); /* v_usecount++ */
142: *a->a_vpp = dvp;
143: DPRINTF("done.(.)\n");
144: return 0;
145: }
146:
147: /* ".." and reguler file. */
148: if ((error = v7fs_file_lookup_by_name(fs, parent, name, &ino))) {
149: /* Not found. Tell this entry be able to allocate. */
150: if (((nameiop == CREATE) || (nameiop == RENAME)) && islastcn) {
151: /* Check directory permission to allocate. */
152: if ((error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred))) {
153: DPRINTF("access denied. (%s)\n", name);
154: return error;
155: }
156: DPRINTF("EJUSTRETURN op=%d (%s)\n", nameiop, name);
157: return EJUSTRETURN;
158: }
159: DPRINTF("lastcn=%d\n", flags & ISLASTCN);
160: return error;
161: }
162:
1.7 njoly 163: if ((nameiop == DELETE) && islastcn) {
164: if ((error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred))) {
165: DPRINTF("access denied. (%s)\n", name);
166: return error;
167: }
168: }
169:
1.1 uch 170: /* Entry found. Allocate v-node */
171: // Check permissions?
172: vpp = 0;
173: if (isdotdot) {
174: VOP_UNLOCK(dvp); /* preserve reference count. (not vput) */
175: }
176: DPRINTF("enter vget\n");
177: if ((error = v7fs_vget(dvp->v_mount, ino, &vpp))) {
178: DPRINTF("***can't get vnode.\n");
179: return error;
180: }
181: DPRINTF("exit vget\n");
182: if (isdotdot) {
183: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
184: }
1.11.2.2 tls 185: if (vpp != dvp)
186: VOP_UNLOCK(vpp);
1.1 uch 187: *a->a_vpp = vpp;
1.6 uch 188: DPRINTF("done.(%s)\n", name);
1.1 uch 189:
190: return 0;
191: }
192:
193: int
194: v7fs_create(void *v)
195: {
1.11.2.2 tls 196: struct vop_create_v3_args /* {
1.1 uch 197: struct vnode *a_dvp;
198: struct vnode **a_vpp;
199: struct componentname *a_cnp;
200: struct vattr *a_vap;
201: } */ *a = v;
202: struct v7fs_node *parent_node = a->a_dvp->v_data;
203: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
204: struct v7fs_self *fs = v7fsmount->core;
205: struct mount *mp = v7fsmount->mountp;
206: struct v7fs_fileattr attr;
207: struct vattr *va = a->a_vap;
208: kauth_cred_t cr = a->a_cnp->cn_cred;
209: v7fs_ino_t ino;
210: int error = 0;
211:
212: DPRINTF("%s parent#%d\n", a->a_cnp->cn_nameptr,
213: parent_node->inode.inode_number);
214: KDASSERT((va->va_type == VREG) || (va->va_type == VSOCK));
215:
216: memset(&attr, 0, sizeof(attr));
217: attr.uid = kauth_cred_geteuid(cr);
218: attr.gid = kauth_cred_getegid(cr);
219: attr.mode = va->va_mode | vtype_to_v7fs_mode (va->va_type);
220: attr.device = 0;
221:
222: /* Allocate disk entry. and register its entry to parent directory. */
223: if ((error = v7fs_file_allocate(fs, &parent_node->inode,
224: a->a_cnp->cn_nameptr, &attr, &ino))) {
225: DPRINTF("v7fs_file_allocate failed.\n");
1.11.2.2 tls 226: return error;
1.1 uch 227: }
228: /* Sync dirent size change. */
229: uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode));
230:
231: /* Get myself vnode. */
232: *a->a_vpp = 0;
233: if ((error = v7fs_vget(mp, ino, a->a_vpp))) {
234: DPRINTF("v7fs_vget failed.\n");
1.11.2.2 tls 235: return error;
1.1 uch 236: }
237:
238: /* Scheduling update time. real update by v7fs_update */
239: struct v7fs_node *newnode = (*a->a_vpp)->v_data;
240: newnode->update_ctime = true;
241: newnode->update_mtime = true;
242: newnode->update_atime = true;
243: DPRINTF("allocated %s->#%d\n", a->a_cnp->cn_nameptr, ino);
244:
1.11.2.2 tls 245: if (error == 0)
246: VOP_UNLOCK(*a->a_vpp);
1.1 uch 247:
248: return error;
249: }
250:
251: int
252: v7fs_mknod(void *v)
253: {
1.11.2.2 tls 254: struct vop_mknod_v3_args /* {
1.1 uch 255: struct vnode *a_dvp;
256: struct vnode **a_vpp;
257: struct componentname *a_cnp;
258: struct vattr *a_vap;
259: } */ *a = v;
260: struct componentname *cnp = a->a_cnp;
261: kauth_cred_t cr = cnp->cn_cred;
262: struct vnode *dvp = a->a_dvp;
263: struct vattr *va = a->a_vap;
264: struct v7fs_node *parent_node = dvp->v_data;
265: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
266: struct v7fs_self *fs = v7fsmount->core;
267: struct mount *mp = v7fsmount->mountp;
268: struct v7fs_fileattr attr;
269:
270: v7fs_ino_t ino;
271: int error = 0;
272:
273: DPRINTF("%s %06o %lx %d\n", cnp->cn_nameptr, va->va_mode,
274: (long)va->va_rdev, va->va_type);
275: memset(&attr, 0, sizeof(attr));
276: attr.uid = kauth_cred_geteuid(cr);
277: attr.gid = kauth_cred_getegid(cr);
278: attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type);
279: attr.device = va->va_rdev;
280:
281: if ((error = v7fs_file_allocate(fs, &parent_node->inode,
282: cnp->cn_nameptr, &attr, &ino)))
1.11.2.2 tls 283: return error;
1.1 uch 284: /* Sync dirent size change. */
285: uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
286:
287: if ((error = v7fs_vget(mp, ino, a->a_vpp))) {
288: DPRINTF("can't get vnode.\n");
1.11.2.2 tls 289: return error;
1.1 uch 290: }
291: struct v7fs_node *newnode = (*a->a_vpp)->v_data;
292: newnode->update_ctime = true;
293: newnode->update_mtime = true;
294: newnode->update_atime = true;
295:
1.11.2.2 tls 296: if (error == 0)
297: VOP_UNLOCK(*a->a_vpp);
1.1 uch 298:
299: return error;
300: }
301:
302: int
303: v7fs_open(void *v)
304: {
305: struct vop_open_args /* {
306: struct vnode *a_vp;
307: int a_mode;
308: kauth_cred_t a_cred;
309: } */ *a = v;
310:
311: struct vnode *vp = a->a_vp;
312: struct v7fs_node *v7node = vp->v_data;
313: struct v7fs_inode *inode = &v7node->inode;
314:
315: DPRINTF("inode %d\n", inode->inode_number);
316: /* Append mode file pointer is managed by kernel. */
317: if (inode->append_mode &&
318: ((a->a_mode & (FWRITE | O_APPEND)) == FWRITE)) {
319: DPRINTF("file is already opened by append mode.\n");
320: return EPERM;
321: }
322:
323: return 0;
324: }
325:
326: int
327: v7fs_close(void *v)
328: {
329: struct vop_close_args /* {
330: struct vnodeop_desc *a_desc;
331: struct vnode *a_vp;
332: int a_fflag;
333: kauth_cred_t a_cred;
334: } */ *a = v;
335: struct vnode *vp = a->a_vp;
336: #ifdef V7FS_VNOPS_DEBUG
337: struct v7fs_node *v7node = vp->v_data;
338: struct v7fs_inode *inode = &v7node->inode;
339: #endif
340: DPRINTF("#%d (i)%dbyte (v)%zubyte\n", inode->inode_number,
341: v7fs_inode_filesize(inode), vp->v_size);
342:
343: /* Update timestamp */
344: v7fs_update(vp, 0, 0, UPDATE_WAIT);
345:
346: return 0;
347: }
348:
349: static int
350: v7fs_check_possible(struct vnode *vp, struct v7fs_node *v7node,
351: mode_t mode)
352: {
353:
354: if (!(mode & VWRITE))
355: return 0;
356:
357: switch (vp->v_type) {
358: default:
359: /* special file is always writable. */
360: return 0;
361: case VDIR:
362: case VLNK:
363: case VREG:
364: break;
365: }
366:
367: return vp->v_mount->mnt_flag & MNT_RDONLY ? EROFS : 0;
368: }
369:
370: static int
371: v7fs_check_permitted(struct vnode *vp, struct v7fs_node *v7node,
372: mode_t mode, kauth_cred_t cred)
373: {
374:
375: struct v7fs_inode *inode = &v7node->inode;
376:
1.11.2.1 tls 377: return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,
1.8 elad 378: vp->v_type, inode->mode), vp, NULL, genfs_can_access(vp->v_type,
379: inode->mode, inode->uid, inode->gid, mode, cred));
1.1 uch 380: }
381:
382: int
383: v7fs_access(void *v)
384: {
385: struct vop_access_args /* {
386: struct vnode *a_vp;
387: int a_mode;
388: kauth_cred_t a_cred;
389: } */ *ap = v;
390: struct vnode *vp = ap->a_vp;
391: struct v7fs_node *v7node = vp->v_data;
392: int error;
393:
394: error = v7fs_check_possible(vp, v7node, ap->a_mode);
395: if (error)
396: return error;
397:
398: error = v7fs_check_permitted(vp, v7node, ap->a_mode, ap->a_cred);
399:
400: return error;
401: }
402:
403: int
404: v7fs_getattr(void *v)
405: {
406: struct vop_getattr_args /* {
407: struct vnode *a_vp;
408: struct vattr *a_vap;
409: kauth_cred_t a_cred;
410: } */ *ap = v;
411: struct vnode *vp = ap->a_vp;
412: struct v7fs_node *v7node = vp->v_data;
413: struct v7fs_inode *inode = &v7node->inode;
414: struct v7fs_mount *v7fsmount = v7node->v7fsmount;
415: struct vattr *vap = ap->a_vap;
416:
417: DPRINTF("\n");
418: vap->va_type = vp->v_type;
419: vap->va_mode = inode->mode;
420: vap->va_nlink = inode->nlink;
421: vap->va_uid = inode->uid;
422: vap->va_gid = inode->gid;
423: vap->va_fsid = v7fsmount->devvp->v_rdev;
424: vap->va_fileid = inode->inode_number;
425: vap->va_size = vp->v_size;
1.11.2.3! jdolecek 426: if (vp->v_type == VLNK) {
! 427: /* Ajust for trailing NUL. */
! 428: KASSERT(vap->va_size > 0);
! 429: vap->va_size -= 1;
! 430: }
1.1 uch 431: vap->va_atime.tv_sec = inode->atime;
432: vap->va_mtime.tv_sec = inode->mtime;
433: vap->va_ctime.tv_sec = inode->ctime;
434: vap->va_birthtime.tv_sec = 0;
435: vap->va_gen = 1;
1.10 njoly 436: vap->va_flags = inode->append_mode ? SF_APPEND : 0;
1.1 uch 437: vap->va_rdev = inode->device;
438: vap->va_bytes = vap->va_size; /* No sparse support. */
439: vap->va_filerev = 0;
440: vap->va_vaflags = 0;
441: /* PAGE_SIZE is larger than sizeof(struct dirent). OK.
442: getcwd_scandir()@vfs_getcwd.c */
443: vap->va_blocksize = PAGE_SIZE;
444:
445: return 0;
446: }
447:
448: int
449: v7fs_setattr(void *v)
450: {
451: struct vop_setattr_args /* {
452: struct vnode *a_vp;
453: struct vattr *a_vap;
454: kauth_cred_t a_cred;
455: struct proc *p;
456: } */ *ap = v;
457: struct vnode *vp = ap->a_vp;
458: struct vattr *vap = ap->a_vap;
459: struct v7fs_node *v7node = vp->v_data;
460: struct v7fs_self *fs = v7node->v7fsmount->core;
461: struct v7fs_inode *inode = &v7node->inode;
1.6 uch 462: kauth_cred_t cred = ap->a_cred;
1.2 uch 463: struct timespec *acc, *mod;
1.1 uch 464: int error = 0;
1.2 uch 465: acc = mod = NULL;
1.1 uch 466:
467: DPRINTF("\n");
468:
469: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
470: switch (vp->v_type) {
471: default:
472: /* special file is always writable. */
473: break;
474: case VDIR:
475: case VLNK:
476: case VREG:
477: DPRINTF("read-only mount\n");
478: return EROFS;
479: }
480: }
481:
482: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
483: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
484: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
485: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
486: DPRINTF("invalid request\n");
487: return EINVAL;
488: }
489: /* File pointer mode. */
1.10 njoly 490: if (vap->va_flags != VNOVAL) {
1.8 elad 491: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_FLAGS,
492: vp, NULL, genfs_can_chflags(cred, vp->v_type, inode->uid,
493: false));
494: if (error)
495: return error;
1.10 njoly 496: inode->append_mode = vap->va_flags & SF_APPEND;
1.1 uch 497: }
498:
499: /* File size change. */
500: if ((vap->va_size != VNOVAL) && (vp->v_type == VREG)) {
501: error = v7fs_datablock_size_change(fs, vap->va_size, inode);
1.11.2.3! jdolecek 502: if (error == 0) {
1.1 uch 503: uvm_vnp_setsize(vp, vap->va_size);
1.11.2.3! jdolecek 504: v7node->update_mtime = true;
! 505: v7node->update_ctime = true;
! 506: }
1.1 uch 507: }
1.6 uch 508: uid_t uid = inode->uid;
509: gid_t gid = inode->gid;
1.1 uch 510:
1.2 uch 511: if (vap->va_uid != (uid_t)VNOVAL) {
1.6 uch 512: uid = vap->va_uid;
513: error = kauth_authorize_vnode(cred,
514: KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
1.8 elad 515: genfs_can_chown(cred, inode->uid, inode->gid, uid,
1.6 uch 516: gid));
517: if (error)
518: return error;
519: inode->uid = uid;
1.2 uch 520: }
521: if (vap->va_gid != (uid_t)VNOVAL) {
1.6 uch 522: gid = vap->va_gid;
523: error = kauth_authorize_vnode(cred,
524: KAUTH_VNODE_CHANGE_OWNERSHIP, vp, NULL,
1.8 elad 525: genfs_can_chown(cred, inode->uid, inode->gid, uid,
1.6 uch 526: gid));
527: if (error)
528: return error;
529: inode->gid = gid;
1.2 uch 530: }
531: if (vap->va_mode != (mode_t)VNOVAL) {
1.6 uch 532: mode_t mode = vap->va_mode;
533: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY,
1.8 elad 534: vp, NULL, genfs_can_chmod(vp->v_type, cred, inode->uid, inode->gid,
1.6 uch 535: mode));
536: if (error) {
537: return error;
538: }
539: v7fs_inode_chmod(inode, mode);
1.2 uch 540: }
1.8 elad 541: if ((vap->va_atime.tv_sec != VNOVAL) ||
542: (vap->va_mtime.tv_sec != VNOVAL) ||
543: (vap->va_ctime.tv_sec != VNOVAL)) {
544: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
1.9 njoly 545: NULL, genfs_can_chtimes(vp, vap->va_vaflags, inode->uid,
1.8 elad 546: cred));
547: if (error)
548: return error;
549:
550: if (vap->va_atime.tv_sec != VNOVAL) {
551: acc = &vap->va_atime;
552: }
553: if (vap->va_mtime.tv_sec != VNOVAL) {
554: mod = &vap->va_mtime;
555: v7node->update_mtime = true;
556: }
557: if (vap->va_ctime.tv_sec != VNOVAL) {
558: v7node->update_ctime = true;
559: }
1.2 uch 560: }
1.1 uch 561:
1.2 uch 562: v7node->update_atime = true;
563: v7fs_update(vp, acc, mod, 0);
1.1 uch 564:
565: return error;
566: }
567:
568: int
569: v7fs_read(void *v)
570: {
571: struct vop_read_args /* {
572: struct vnode *a_vp;
573: struct uio *a_uio;
574: int a_ioflag;
575: kauth_cred_t a_cred;
576: } */ *a = v;
577: struct vnode *vp = a->a_vp;
578: struct uio *uio = a->a_uio;
579: struct v7fs_node *v7node = vp->v_data;
580: struct v7fs_inode *inode = &v7node->inode;
581: vsize_t sz, filesz = v7fs_inode_filesize(inode);
582: const int advice = IO_ADV_DECODE(a->a_ioflag);
583: int error = 0;
584:
585: DPRINTF("type=%d inode=%d\n", vp->v_type, v7node->inode.inode_number);
586:
587: while (uio->uio_resid > 0) {
588: if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0)
589: break;
590:
591: error = ubc_uiomove(&vp->v_uobj, uio, sz, advice, UBC_READ |
592: UBC_PARTIALOK | UBC_UNMAP_FLAG(v));
593: if (error) {
594: break;
595: }
596: DPRINTF("read %zubyte\n", sz);
597: }
598: v7node->update_atime = true;
599:
1.11.2.2 tls 600: return error;
1.1 uch 601: }
602:
603: int
604: v7fs_write(void *v)
605: {
606: struct vop_write_args /* {
607: struct vnode *a_vp;
608: struct uio *a_uio;
609: int a_ioflag;
610: kauth_cred_t a_cred;
611: } */ *a = v;
612: struct vnode *vp = a->a_vp;
613: struct uio *uio = a->a_uio;
614: int advice = IO_ADV_DECODE(a->a_ioflag);
615: struct v7fs_node *v7node = vp->v_data;
616: struct v7fs_inode *inode = &v7node->inode;
617: struct v7fs_self *fs = v7node->v7fsmount->core;
618: vsize_t sz;
619: int error = 0;
620:
621: if (uio->uio_resid == 0)
622: return 0;
623:
624: sz = v7fs_inode_filesize(inode);
625: DPRINTF("(i)%ld (v)%zu ofs=%zu + res=%zu = %zu\n", sz, vp->v_size,
626: uio->uio_offset, uio->uio_resid, uio->uio_offset + uio->uio_resid);
627:
628: /* Append mode file offset is managed by kernel. */
629: if (a->a_ioflag & IO_APPEND)
630: uio->uio_offset = sz;
631:
632: /* If write region is over filesize, expand. */
633: size_t newsize= uio->uio_offset + uio->uio_resid;
634: ssize_t expand = newsize - sz;
635: if (expand > 0) {
636: if ((error = v7fs_datablock_expand(fs, inode, expand)))
637: return error;
638: uvm_vnp_setsize(vp, newsize);
639: }
640:
641: while (uio->uio_resid > 0) {
642: sz = uio->uio_resid;
643: if ((error = ubc_uiomove(&vp->v_uobj, uio, sz, advice,
644: UBC_WRITE | UBC_UNMAP_FLAG(v))))
645: break;
646: DPRINTF("write %zubyte\n", sz);
647: }
648: v7node->update_mtime = true;
649:
650: return error;
651: }
652:
653: int
654: v7fs_fsync(void *v)
655: {
656: struct vop_fsync_args /* {
657: struct vnode *a_vp;
658: kauth_cred_t a_cred;
659: int a_flags;
660: off_t offlo;
661: off_t offhi;
662: } */ *a = v;
663: struct vnode *vp = a->a_vp;
664: int error, wait;
665:
666: DPRINTF("%p\n", a->a_vp);
667: if (a->a_flags & FSYNC_CACHE) {
668: return EOPNOTSUPP;
669: }
670:
671: wait = (a->a_flags & FSYNC_WAIT);
1.11 chs 672: error = vflushbuf(vp, a->a_flags);
1.1 uch 673:
674: if (error == 0 && (a->a_flags & FSYNC_DATAONLY) == 0)
675: error = v7fs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
676:
677: return error;
678: }
679:
680: int
681: v7fs_remove(void *v)
682: {
1.11.2.3! jdolecek 683: struct vop_remove_v2_args /* {
1.1 uch 684: struct vnodeop_desc *a_desc;
685: struct vnode * a_dvp;
686: struct vnode * a_vp;
687: struct componentname * a_cnp;
688: } */ *a = v;
689: struct v7fs_node *parent_node = a->a_dvp->v_data;
690: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
691: struct vnode *vp = a->a_vp;
692: struct vnode *dvp = a->a_dvp;
1.11.2.3! jdolecek 693: struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
1.1 uch 694: struct v7fs_self *fs = v7fsmount->core;
695: int error = 0;
696:
697: DPRINTF("delete %s\n", a->a_cnp->cn_nameptr);
698:
699: if (vp->v_type == VDIR) {
700: error = EPERM;
701: goto out;
702: }
703:
704: if ((error = v7fs_file_deallocate(fs, &parent_node->inode,
705: a->a_cnp->cn_nameptr))) {
706: DPRINTF("v7fs_file_delete failed.\n");
707: goto out;
708: }
1.11.2.3! jdolecek 709: error = v7fs_inode_load(fs, inode, inode->inode_number);
! 710: if (error)
! 711: goto out;
1.1 uch 712: /* Sync dirent size change. */
713: uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
714:
715: out:
716: if (dvp == vp)
717: vrele(vp); /* v_usecount-- of unlocked vp */
718: else
719: vput(vp); /* unlock vp and then v_usecount-- */
720:
721: return error;
722: }
723:
724: int
725: v7fs_link(void *v)
726: {
1.11.2.3! jdolecek 727: struct vop_link_v2_args /* {
1.1 uch 728: struct vnode *a_dvp;
729: struct vnode *a_vp;
730: struct componentname *a_cnp;
731: } */ *a = v;
732: struct vnode *dvp = a->a_dvp;
733: struct vnode *vp = a->a_vp;
734: struct v7fs_node *parent_node = dvp->v_data;
735: struct v7fs_node *node = vp->v_data;
736: struct v7fs_inode *parent = &parent_node->inode;
737: struct v7fs_inode *p = &node->inode;
738: struct v7fs_self *fs = node->v7fsmount->core;
739: struct componentname *cnp = a->a_cnp;
740: int error = 0;
741:
742: DPRINTF("%p\n", vp);
743: /* Lock soruce file */
744: if ((error = vn_lock(vp, LK_EXCLUSIVE))) {
745: DPRINTF("lock failed. %p\n", vp);
746: VOP_ABORTOP(dvp, cnp);
747: goto unlock;
748: }
749: error = v7fs_file_link(fs, parent, p, cnp->cn_nameptr);
750: /* Sync dirent size change. */
751: uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
752:
753: VOP_UNLOCK(vp);
754: unlock:
755: return error;
756: }
757:
758: int
759: v7fs_rename(void *v)
760: {
761: struct vop_rename_args /* {
762: struct vnode *a_fdvp; from parent-directory
763: struct vnode *a_fvp; from file
764: struct componentname *a_fcnp;
765: struct vnode *a_tdvp; to parent-directory
766: struct vnode *a_tvp; to file
767: struct componentname *a_tcnp;
768: } */ *a = v;
769: struct vnode *fvp = a->a_fvp;
770: struct vnode *tvp = a->a_tvp;
771: struct vnode *fdvp = a->a_fdvp;
772: struct vnode *tdvp = a->a_tdvp;
773: struct v7fs_node *parent_from = fdvp->v_data;
774: struct v7fs_node *parent_to = tdvp->v_data;
775: struct v7fs_node *v7node = fvp->v_data;
776: struct v7fs_self *fs = v7node->v7fsmount->core;
777: const char *from_name = a->a_fcnp->cn_nameptr;
778: const char *to_name = a->a_tcnp->cn_nameptr;
779: int error;
780:
1.6 uch 781: DPRINTF("%s->%s %p %p\n", from_name, to_name, fvp, tvp);
782:
1.1 uch 783: if ((fvp->v_mount != tdvp->v_mount) ||
784: (tvp && (fvp->v_mount != tvp->v_mount))) {
785: error = EXDEV;
786: DPRINTF("cross-device link\n");
787: goto out;
788: }
789: // XXXsource file lock?
790: error = v7fs_file_rename(fs, &parent_from->inode, from_name,
791: &parent_to->inode, to_name);
1.6 uch 792: /* 'to file' inode may be changed. (hard-linked and it is cached.)
793: t_vnops rename_reg_nodir */
1.11.2.3! jdolecek 794: if (error == 0 && tvp) {
! 795: struct v7fs_inode *inode =
! 796: &((struct v7fs_node *)tvp->v_data)->inode;
! 797:
! 798: error = v7fs_inode_load(fs, inode, inode->inode_number);
! 799: uvm_vnp_setsize(tvp, v7fs_inode_filesize(inode));
1.6 uch 800: }
1.1 uch 801: /* Sync dirent size change. */
802: uvm_vnp_setsize(tdvp, v7fs_inode_filesize(&parent_to->inode));
803: uvm_vnp_setsize(fdvp, v7fs_inode_filesize(&parent_from->inode));
804: out:
805: if (tvp)
806: vput(tvp); /* locked on entry */
807: if (tdvp == tvp)
808: vrele(tdvp);
809: else
810: vput(tdvp);
811: vrele(fdvp);
812: vrele(fvp);
813:
814: return error;
815: }
816:
817: int
818: v7fs_mkdir(void *v)
819: {
1.11.2.2 tls 820: struct vop_mkdir_v3_args /* {
1.1 uch 821: struct vnode *a_dvp;
822: struct vnode **a_vpp;
823: struct componentname *a_cnp;
824: struct vattr *a_vap;
825: } */ *a = v;
826: struct componentname *cnp = a->a_cnp;
827: kauth_cred_t cr = cnp->cn_cred;
828: struct vnode *dvp = a->a_dvp;
829: struct vattr *va = a->a_vap;
830: struct v7fs_node *parent_node = dvp->v_data;
831: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
832: struct v7fs_self *fs = v7fsmount->core;
833: struct v7fs_fileattr attr;
834: struct mount *mp = v7fsmount->mountp;
835: v7fs_ino_t ino;
836: int error = 0;
837:
838: DPRINTF("\n");
839: memset(&attr, 0, sizeof(attr));
840: attr.uid = kauth_cred_geteuid(cr);
841: attr.gid = kauth_cred_getegid(cr);
842: attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type);
843:
844: if ((error = v7fs_file_allocate(fs, &parent_node->inode,
845: cnp->cn_nameptr, &attr, &ino)))
1.11.2.2 tls 846: return error;
1.1 uch 847: /* Sync dirent size change. */
848: uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
849:
850: if ((error = v7fs_vget(mp, ino, a->a_vpp))) {
851: DPRINTF("can't get vnode.\n");
852: }
853: struct v7fs_node *newnode = (*a->a_vpp)->v_data;
854: newnode->update_ctime = true;
855: newnode->update_mtime = true;
856: newnode->update_atime = true;
857:
1.11.2.2 tls 858: if (error == 0)
859: VOP_UNLOCK(*a->a_vpp);
1.1 uch 860:
861: return error;
862: }
863:
864: int
865: v7fs_rmdir(void *v)
866: {
1.11.2.3! jdolecek 867: struct vop_rmdir_v2_args /* {
1.1 uch 868: struct vnode *a_dvp;
869: struct vnode *a_vp;
870: struct componentname *a_cnp;
871: } */ *a = v;
872: struct vnode *vp = a->a_vp;
873: struct vnode *dvp = a->a_dvp;
874: struct v7fs_node *parent_node = dvp->v_data;
875: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
876: struct v7fs_inode *inode = &((struct v7fs_node *)vp->v_data)->inode;
877: struct v7fs_self *fs = v7fsmount->core;
878: int error = 0;
879:
880: DPRINTF("delete %s\n", a->a_cnp->cn_nameptr);
881:
882: KDASSERT(vp->v_type == VDIR);
883:
884: if ((error = v7fs_file_deallocate(fs, &parent_node->inode,
885: a->a_cnp->cn_nameptr))) {
886: DPRINTF("v7fs_directory_deallocate failed.\n");
887: goto out;
888: }
1.11.2.3! jdolecek 889: error = v7fs_inode_load(fs, inode, inode->inode_number);
! 890: if (error)
! 891: goto out;
! 892: uvm_vnp_setsize(vp, v7fs_inode_filesize(inode));
1.1 uch 893: /* Sync dirent size change. */
894: uvm_vnp_setsize(dvp, v7fs_inode_filesize(&parent_node->inode));
895: out:
896: vput(vp);
897:
898: return error;
899: }
900:
901: struct v7fs_readdir_arg {
902: struct dirent *dp;
903: struct uio *uio;
904: int start;
905: int end;
906: int cnt;
907: };
908: static int readdir_subr(struct v7fs_self *, void *, v7fs_daddr_t, size_t);
909:
910: int
911: readdir_subr(struct v7fs_self *fs, void *ctx, v7fs_daddr_t blk, size_t sz)
912: {
913: struct v7fs_readdir_arg *p = (struct v7fs_readdir_arg *)ctx;
914: struct v7fs_dirent *dir;
915: struct dirent *dp = p->dp;
916: struct v7fs_inode inode;
917: char filename[V7FS_NAME_MAX + 1];
918: int i, n;
919: int error = 0;
920: void *buf;
921:
922: if (!(buf = scratch_read(fs, blk)))
923: return EIO;
924: dir = (struct v7fs_dirent *)buf;
925:
926: n = sz / sizeof(*dir);
927:
928: for (i = 0; (i < n) && (p->cnt < p->end); i++, dir++, p->cnt++) {
929: if (p->cnt < p->start)
930: continue;
931:
932: if ((error = v7fs_inode_load(fs, &inode, dir->inode_number)))
933: break;
934:
935: v7fs_dirent_filename(filename, dir->name);
936:
937: DPRINTF("inode=%d name=%s %s\n", dir->inode_number, filename,
938: v7fs_inode_isdir(&inode) ? "DIR" : "FILE");
939: memset(dp, 0, sizeof(*dp));
940: dp->d_fileno = dir->inode_number;
941: dp->d_type = v7fs_mode_to_d_type(inode.mode);
942: dp->d_namlen = strlen(filename);
943: strcpy(dp->d_name, filename);
944: dp->d_reclen = sizeof(*dp);
945: if ((error = uiomove(dp, dp->d_reclen, p->uio))) {
946: DPRINTF("uiomove failed.\n");
947: break;
948: }
949: }
950: scratch_free(fs, buf);
951:
1.3 uch 952: if (p->cnt == p->end)
953: return V7FS_ITERATOR_BREAK;
954:
1.1 uch 955: return error;
956: }
957:
958: int
959: v7fs_readdir(void *v)
960: {
961: struct vop_readdir_args /* {
962: struct vnode *a_vp;
963: struct uio *a_uio;
964: kauth_cred_t a_cred;
965: int *a_eofflag;
966: off_t **a_cookies;
967: int *a_ncookies;
968: } */ *a = v;
969: struct uio *uio = a->a_uio;
970: struct vnode *vp = a->a_vp;
971: struct v7fs_node *v7node = vp->v_data;
972: struct v7fs_inode *inode = &v7node->inode;
973: struct v7fs_self *fs = v7node->v7fsmount->core;
974: struct dirent *dp;
975: int error;
976:
977: DPRINTF("offset=%zu residue=%zu\n", uio->uio_offset, uio->uio_resid);
978:
979: KDASSERT(vp->v_type == VDIR);
980: KDASSERT(uio->uio_offset >= 0);
981: KDASSERT(v7fs_inode_isdir(inode));
982:
983: struct v7fs_readdir_arg arg;
984: arg.start = uio->uio_offset / sizeof(*dp);
985: arg.end = arg.start + uio->uio_resid / sizeof(*dp);
986: if (arg.start == arg.end) {/* user buffer has not enuf space. */
987: DPRINTF("uio buffer too small\n");
988: return ENOMEM;
989: }
1.11.2.2 tls 990: dp = kmem_zalloc(sizeof(*dp), KM_SLEEP);
1.1 uch 991: arg.cnt = 0;
992: arg.dp = dp;
993: arg.uio = uio;
994:
995: *a->a_eofflag = false;
996: error = v7fs_datablock_foreach(fs, inode, readdir_subr, &arg);
997: if (error == V7FS_ITERATOR_END) {
998: *a->a_eofflag = true;
999: }
1000: if (error < 0)
1001: error = 0;
1002:
1.11.2.2 tls 1003: kmem_free(dp, sizeof(*dp));
1.1 uch 1004:
1005: return error;
1006: }
1007:
1008: int
1009: v7fs_inactive(void *v)
1010: {
1.11.2.3! jdolecek 1011: struct vop_inactive_v2_args /* {
1.1 uch 1012: struct vnode *a_vp;
1013: bool *a_recycle;
1014: } */ *a = v;
1015: struct vnode *vp = a->a_vp;
1016: struct v7fs_node *v7node = vp->v_data;
1017: struct v7fs_inode *inode = &v7node->inode;
1018:
1.5 uch 1019: DPRINTF("%p #%d\n", vp, inode->inode_number);
1.11.2.3! jdolecek 1020: if (v7fs_inode_nlink(inode) > 0) {
1.1 uch 1021: v7fs_update(vp, 0, 0, UPDATE_WAIT);
1.5 uch 1022: *a->a_recycle = false;
1023: } else {
1024: *a->a_recycle = true;
1.1 uch 1025: }
1026:
1027: return 0;
1028: }
1029:
1030: int
1031: v7fs_reclaim(void *v)
1032: {
1033: /*This vnode is no longer referenced by kernel. */
1034: extern struct pool v7fs_node_pool;
1.11.2.3! jdolecek 1035: struct vop_reclaim_v2_args /* {
1.1 uch 1036: struct vnode *a_vp;
1037: } */ *a = v;
1038: struct vnode *vp = a->a_vp;
1039: struct v7fs_node *v7node = vp->v_data;
1.11.2.3! jdolecek 1040: struct v7fs_self *fs = v7node->v7fsmount->core;
! 1041: struct v7fs_inode *inode = &v7node->inode;
! 1042:
! 1043: VOP_UNLOCK(vp);
1.1 uch 1044:
1.11.2.3! jdolecek 1045: DPRINTF("%p #%d\n", vp, inode->inode_number);
! 1046: if (v7fs_inode_nlink(inode) == 0) {
! 1047: v7fs_datablock_size_change(fs, 0, inode);
! 1048: DPRINTF("remove datablock\n");
! 1049: v7fs_inode_deallocate(fs, inode->inode_number);
! 1050: DPRINTF("remove inode\n");
! 1051: }
1.1 uch 1052: genfs_node_destroy(vp);
1053: pool_put(&v7fs_node_pool, v7node);
1.11.2.3! jdolecek 1054: mutex_enter(vp->v_interlock);
1.1 uch 1055: vp->v_data = NULL;
1.11.2.3! jdolecek 1056: mutex_exit(vp->v_interlock);
1.1 uch 1057:
1058: return 0;
1059: }
1060:
1061: int
1062: v7fs_bmap(void *v)
1063: {
1064: struct vop_bmap_args /* {
1065: struct vnode *a_vp;
1066: daddr_t a_bn;
1067: struct vnode **a_vpp;
1068: daddr_t *a_bnp;
1069: int *a_runp;
1070: } */ *a = v;
1071: struct vnode *vp = a->a_vp;
1072: struct v7fs_node *v7node = vp->v_data;
1073: struct v7fs_mount *v7fsmount = v7node->v7fsmount;
1074: struct v7fs_self *fs = v7node->v7fsmount->core;
1075: struct v7fs_inode *inode = &v7node->inode;
1076: int error = 0;
1077:
1078: DPRINTF("inode=%d offset=%zu %p\n", inode->inode_number, a->a_bn, vp);
1079: DPRINTF("filesize: %d\n", inode->filesize);
1080: if (!a->a_bnp)
1081: return 0;
1082:
1083: v7fs_daddr_t blk;
1084: if (!(blk = v7fs_datablock_last(fs, inode,
1085: (a->a_bn + 1) << V7FS_BSHIFT))) {
1086: /* +1 converts block # to file offset. */
1087: return ENOSPC;
1088: }
1089:
1090: *a->a_bnp = blk;
1091:
1092: if (a->a_vpp)
1093: *a->a_vpp = v7fsmount->devvp;
1094: if (a->a_runp)
1095: *a->a_runp = 0; /*XXX TODO */
1096:
1097: DPRINTF("%d %zu->%zu status=%d\n", inode->inode_number, a->a_bn,
1098: *a->a_bnp, error);
1099:
1100: return error;
1101: }
1102:
1103: int
1104: v7fs_strategy(void *v)
1105: {
1106: struct vop_strategy_args /* {
1107: struct vnode *a_vp;
1108: struct buf *a_bp;
1109: } */ *a = v;
1110: struct buf *b = a->a_bp;
1111: struct vnode *vp = a->a_vp;
1112: struct v7fs_node *v7node = vp->v_data;
1113: struct v7fs_mount *v7fsmount = v7node->v7fsmount;
1114: int error;
1115:
1116: DPRINTF("%p\n", vp);
1117: KDASSERT(vp->v_type == VREG);
1118: if (b->b_blkno == b->b_lblkno) {
1119: error = VOP_BMAP(vp, b->b_lblkno, NULL, &b->b_blkno, NULL);
1120: if (error) {
1121: b->b_error = error;
1122: biodone(b);
1123: return error;
1124: }
1125: if ((long)b->b_blkno == -1)
1126: clrbuf(b);
1127: }
1128: if ((long)b->b_blkno == -1) {
1129: biodone(b);
1130: return 0;
1131: }
1132:
1133: return VOP_STRATEGY(v7fsmount->devvp, b);
1134: }
1135:
1136: int
1137: v7fs_print(void *v)
1138: {
1139: struct vop_print_args /* {
1140: struct vnode *a_vp;
1141: } */ *a = v;
1142: struct v7fs_node *v7node = a->a_vp->v_data;
1143:
1144: v7fs_inode_dump(&v7node->inode);
1145:
1146: return 0;
1147: }
1148:
1149: int
1150: v7fs_advlock(void *v)
1151: {
1152: struct vop_advlock_args /* {
1153: struct vnode *a_vp;
1154: void *a_id;
1155: int a_op;
1156: struct flock *a_fl;
1157: int a_flags;
1158: } */ *a = v;
1159: struct v7fs_node *v7node = a->a_vp->v_data;
1160:
1161: DPRINTF("op=%d\n", a->a_op);
1162:
1163: return lf_advlock(a, &v7node->lockf,
1164: v7fs_inode_filesize(&v7node->inode));
1165: }
1166:
1167: int
1168: v7fs_pathconf(void *v)
1169: {
1170: struct vop_pathconf_args /* {
1171: struct vnode *a_vp;
1172: int a_name;
1173: register_t *a_retval;
1174: } */ *a = v;
1175: int err = 0;
1176:
1177: DPRINTF("%p\n", a->a_vp);
1178:
1179: switch (a->a_name) {
1180: case _PC_LINK_MAX:
1181: *a->a_retval = V7FS_LINK_MAX;
1182: break;
1183: case _PC_NAME_MAX:
1184: *a->a_retval = V7FS_NAME_MAX;
1185: break;
1186: case _PC_PATH_MAX:
1187: *a->a_retval = V7FS_PATH_MAX;
1188: break;
1189: case _PC_CHOWN_RESTRICTED:
1190: *a->a_retval = 1;
1191: break;
1192: case _PC_NO_TRUNC:
1193: *a->a_retval = 0;
1194: break;
1195: case _PC_SYNC_IO:
1196: *a->a_retval = 1;
1197: break;
1198: case _PC_FILESIZEBITS:
1199: *a->a_retval = 30; /* ~1G */
1200: break;
1201: case _PC_SYMLINK_MAX:
1.4 uch 1202: *a->a_retval = V7FSBSD_MAXSYMLINKLEN;
1.1 uch 1203: break;
1204: case _PC_2_SYMLINKS:
1205: *a->a_retval = 1;
1206: break;
1207: default:
1208: err = EINVAL;
1209: break;
1210: }
1211:
1212: return err;
1213: }
1214:
1215: int
1216: v7fs_update(struct vnode *vp, const struct timespec *acc,
1217: const struct timespec *mod, int flags)
1218: {
1219: struct v7fs_node *v7node = vp->v_data;
1220: struct v7fs_inode *inode = &v7node->inode;
1221: struct v7fs_self *fs = v7node->v7fsmount->core;
1222: bool update = false;
1223:
1224: DPRINTF("%p %zu %d\n", vp, vp->v_size, v7fs_inode_filesize(inode));
1225: KDASSERT(vp->v_size == v7fs_inode_filesize(inode));
1226:
1227: if (v7node->update_atime) {
1228: inode->atime = acc ? acc->tv_sec : time_second;
1229: v7node->update_atime = false;
1230: update = true;
1231: }
1232: if (v7node->update_ctime) {
1233: inode->ctime = time_second;
1234: v7node->update_ctime = false;
1235: update = true;
1236: }
1237: if (v7node->update_mtime) {
1238: inode->mtime = mod ? mod->tv_sec : time_second;
1239: v7node->update_mtime = false;
1240: update = true;
1241: }
1242:
1243: if (update)
1244: v7fs_inode_writeback(fs, inode);
1245:
1246: return 0;
1247: }
1248:
1249: int
1250: v7fs_symlink(void *v)
1251: {
1.11.2.2 tls 1252: struct vop_symlink_v3_args /* {
1.1 uch 1253: struct vnode *a_dvp;
1254: struct vnode **a_vpp;
1255: struct componentname *a_cnp;
1256: struct vattr *a_vap;
1257: char *a_target;
1258: } */ *a = v;
1259: struct v7fs_node *parent_node = a->a_dvp->v_data;
1260: struct v7fs_mount *v7fsmount = parent_node->v7fsmount;
1261: struct v7fs_self *fs = v7fsmount->core;
1262: struct vattr *va = a->a_vap;
1263: kauth_cred_t cr = a->a_cnp->cn_cred;
1264: struct componentname *cnp = a->a_cnp;
1265: struct v7fs_fileattr attr;
1266: v7fs_ino_t ino;
1267: const char *from = a->a_target;
1268: const char *to = cnp->cn_nameptr;
1269: size_t len = strlen(from) + 1;
1270: int error = 0;
1271:
1272: if (len > V7FS_BSIZE) { /* limited to 512byte pathname */
1273: DPRINTF("too long pathname.");
1274: return ENAMETOOLONG;
1275: }
1276:
1277: memset(&attr, 0, sizeof(attr));
1278: attr.uid = kauth_cred_geteuid(cr);
1279: attr.gid = kauth_cred_getegid(cr);
1280: attr.mode = va->va_mode | vtype_to_v7fs_mode(va->va_type);
1281:
1282: if ((error = v7fs_file_allocate
1283: (fs, &parent_node->inode, to, &attr, &ino))) {
1.11.2.2 tls 1284: return error;
1.1 uch 1285: }
1286: /* Sync dirent size change. */
1287: uvm_vnp_setsize(a->a_dvp, v7fs_inode_filesize(&parent_node->inode));
1288:
1289: /* Get myself vnode. */
1290: if ((error = v7fs_vget(v7fsmount->mountp, ino, a->a_vpp))) {
1291: DPRINTF("can't get vnode.\n");
1292: }
1293:
1294: struct v7fs_node *newnode = (*a->a_vpp)->v_data;
1295: struct v7fs_inode *p = &newnode->inode;
1.4 uch 1296: v7fs_file_symlink(fs, p, from);
1.1 uch 1297: uvm_vnp_setsize(*a->a_vpp, v7fs_inode_filesize(p));
1298:
1299: newnode->update_ctime = true;
1300: newnode->update_mtime = true;
1301: newnode->update_atime = true;
1.11.2.2 tls 1302:
1303: if (error == 0)
1304: VOP_UNLOCK(*a->a_vpp);
1.1 uch 1305:
1306: return error;
1307: }
1308:
1309: int
1310: v7fs_readlink(void *v)
1311: {
1312: struct vop_readlink_args /* {
1313: struct vnode *a_vp;
1314: struct uio *a_uio;
1315: kauth_cred_t a_cred;
1316: } */ *a = v;
1317: struct uio *uio = a->a_uio;
1318: struct vnode *vp = a->a_vp;
1319: struct v7fs_node *v7node = vp->v_data;
1320: struct v7fs_inode *inode = &v7node->inode;
1321: struct v7fs_self *fs = v7node->v7fsmount->core;
1322: int error = 0;
1323:
1324: KDASSERT(vp->v_type == VLNK);
1325: KDASSERT(uio->uio_offset >= 0);
1326: KDASSERT(v7fs_inode_islnk(inode));
1327:
1328: v7fs_daddr_t blk = inode->addr[0];
1329: void *buf;
1330: if (!(buf = scratch_read(fs, blk))) {
1331: error = EIO;
1332: goto error_exit;
1333: }
1334:
1335: if ((error = uiomove(buf, strlen(buf), uio))) {
1336: DPRINTF("uiomove failed.\n");
1337: }
1338: scratch_free(fs, buf);
1339:
1340: error_exit:
1341: return error;
1342: }
CVSweb <webmaster@jp.NetBSD.org>