Annotation of src/sys/fs/udf/udf_vnops.c, Revision 1.10.8.2
1.10.8.2! matt 1: /* $NetBSD: udf_vnops.c,v 1.10.8.1 2007/11/06 23:31:23 matt Exp $ */
1.1 reinoud 2:
3: /*
4: * Copyright (c) 2006 Reinoud Zandijk
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed for the
18: * NetBSD Project. See http://www.NetBSD.org/ for
19: * information about NetBSD.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: *
34: */
35:
36:
37: #include <sys/cdefs.h>
38: #ifndef lint
1.10.8.2! matt 39: __KERNEL_RCSID(0, "$NetBSD$");
1.1 reinoud 40: #endif /* not lint */
41:
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/namei.h>
46: #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
47: #include <sys/kernel.h>
48: #include <sys/file.h> /* define FWRITE ... */
49: #include <sys/stat.h>
50: #include <sys/buf.h>
51: #include <sys/proc.h>
52: #include <sys/mount.h>
53: #include <sys/vnode.h>
54: #include <sys/signalvar.h>
55: #include <sys/malloc.h>
56: #include <sys/dirent.h>
57: #include <sys/lockf.h>
58:
59: #include <miscfs/genfs/genfs.h>
60: #include <uvm/uvm_extern.h>
61:
62: #include <fs/udf/ecma167-udf.h>
63: #include <fs/udf/udf_mount.h>
64: #include "udf.h"
65: #include "udf_subr.h"
66: #include "udf_bswap.h"
67:
68:
69: #define VTOI(vnode) ((struct udf_node *) vnode->v_data)
70:
71:
72: /* externs */
73: extern int prtactive;
74:
75:
76: /* implementations of vnode functions; table follows at end */
77: /* --------------------------------------------------------------------- */
78:
79: int
80: udf_inactive(void *v)
81: {
82: struct vop_inactive_args /* {
83: struct vnode *a_vp;
84: struct proc *a_p;
85: } */ *ap = v;
86: struct vnode *vp = ap->a_vp;
87:
88: if (prtactive && vp->v_usecount != 0)
89: vprint("udf_inactive(): pushing active", vp);
90:
91: VOP_UNLOCK(vp, 0);
92:
93: DPRINTF(LOCKING, ("udf_inactive called for node %p\n", VTOI(vp)));
94:
95: /*
96: * Optionally flush metadata to disc. If the file has not been
97: * referenced anymore in a directory we ought to free up the resources
98: * on disc if applicable.
99: */
100:
101: return 0;
102: }
103:
104: /* --------------------------------------------------------------------- */
105:
106: int
107: udf_reclaim(void *v)
108: {
109: struct vop_reclaim_args /* {
110: struct vnode *a_vp;
111: } */ *ap = v;
112: struct vnode *vp = ap->a_vp;
113: struct udf_node *node = VTOI(vp);
114:
115: if (prtactive && vp->v_usecount != 0)
116: vprint("udf_reclaim(): pushing active", vp);
117:
118: /* purge old data from namei */
119: cache_purge(vp);
120:
121: DPRINTF(LOCKING, ("udf_reclaim called for node %p\n", node));
122: /* dispose all node knowledge */
123: udf_dispose_node(node);
124:
125: return 0;
126: }
127:
128: /* --------------------------------------------------------------------- */
129:
130: int
131: udf_read(void *v)
132: {
133: struct vop_read_args /* {
134: struct vnode *a_vp;
135: struct uio *a_uio;
136: int a_ioflag;
1.5 elad 137: kauth_cred_t a_cred;
1.1 reinoud 138: } */ *ap = v;
139: struct vnode *vp = ap->a_vp;
140: struct uio *uio = ap->a_uio;
141: int ioflag = ap->a_ioflag;
142: struct uvm_object *uobj;
143: struct udf_node *udf_node = VTOI(vp);
144: struct file_entry *fe;
145: struct extfile_entry *efe;
146: uint64_t file_size;
147: vsize_t len;
148: void *win;
149: int error;
150: int flags;
151:
152: /* XXX how to deal with xtended attributes (files) */
153:
154: DPRINTF(READ, ("udf_read called\n"));
155:
156: /* can this happen? some filingsystems have this check */
157: if (uio->uio_offset < 0)
158: return EINVAL;
159:
160: assert(udf_node);
161: assert(udf_node->fe || udf_node->efe);
162:
163: /* TODO set access time */
164:
165: /* get directory filesize */
166: if (udf_node->fe) {
167: fe = udf_node->fe;
168: file_size = udf_rw64(fe->inf_len);
169: } else {
170: assert(udf_node->efe);
171: efe = udf_node->efe;
172: file_size = udf_rw64(efe->inf_len);
1.6 christos 173: }
1.1 reinoud 174:
175: if (vp->v_type == VDIR) {
176: /* protect against rogue programs reading raw directories */
177: if ((ioflag & IO_ALTSEMANTICS) == 0)
178: return EISDIR;
1.6 christos 179: }
1.1 reinoud 180: if (vp->v_type == VREG || vp->v_type == VDIR) {
181: const int advice = IO_ADV_DECODE(ap->a_ioflag);
182:
183: /* read contents using buffercache */
184: uobj = &vp->v_uobj;
185: flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
186: error = 0;
187: while (uio->uio_resid > 0) {
188: /* reached end? */
189: if (file_size <= uio->uio_offset)
190: break;
191:
192: /* maximise length to file extremity */
193: len = MIN(file_size - uio->uio_offset, uio->uio_resid);
194: if (len == 0)
195: break;
196:
197: /* ubc, here we come, prepare to trap */
198: win = ubc_alloc(uobj, uio->uio_offset, &len,
199: advice, UBC_READ);
200: error = uiomove(win, len, uio);
201: ubc_release(win, flags);
202: if (error)
203: break;
204: }
205: /* TODO note access time */
206: return error;
1.6 christos 207: }
1.1 reinoud 208:
209: return EINVAL;
210: }
211:
212: /* --------------------------------------------------------------------- */
213:
214: int
215: udf_write(void *v)
216: {
217: struct vop_write_args /* {
218: struct vnode *a_vp;
219: struct uio *a_uio;
220: int a_ioflag;
1.5 elad 221: kauth_cred_t a_cred;
1.1 reinoud 222: } */ *ap = v;
223:
224: DPRINTF(NOTIMPL, ("udf_write called\n"));
225: ap = ap; /* shut up gcc */
226:
227: /* TODO implement writing */
228: return EROFS;
229: }
230:
231:
232: /* --------------------------------------------------------------------- */
233:
234: /*
235: * `Special' bmap functionality that translates all incomming requests to
236: * translate to vop_strategy() calls with the same blocknumbers effectively
237: * not translating at all.
238: */
239:
240: int
241: udf_trivial_bmap(void *v)
242: {
243: struct vop_bmap_args /* {
244: struct vnode *a_vp;
245: daddr_t a_bn;
246: struct vnode **a_vpp;
247: daddr_t *a_bnp;
248: int *a_runp;
249: } */ *ap = v;
250: struct vnode *vp = ap->a_vp; /* our node */
251: struct vnode **vpp = ap->a_vpp; /* return node */
252: daddr_t *bnp = ap->a_bnp; /* translated */
253: daddr_t bn = ap->a_bn; /* origional */
254: int *runp = ap->a_runp;
255: struct udf_node *udf_node = VTOI(vp);
256: uint32_t lb_size;
257:
258: /* get logical block size */
259: lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
260:
261: /* could return `-1' to indicate holes/zeros */
262: /* translate 1:1 */
263: *bnp = bn;
264:
265: /* set the vnode to read the data from with strategy on itself */
266: if (vpp)
267: *vpp = vp;
268:
269: /* set runlength of maximum block size */
270: if (runp)
271: *runp = MAXPHYS / lb_size; /* or with -1 ? */
272:
273: /* return success */
274: return 0;
275: }
276:
277: /* --------------------------------------------------------------------- */
278:
279: int
280: udf_strategy(void *v)
281: {
282: struct vop_strategy_args /* {
283: struct vnode *a_vp;
284: struct buf *a_bp;
285: } */ *ap = v;
286: struct vnode *vp = ap->a_vp;
287: struct buf *bp = ap->a_bp;
288: struct udf_node *udf_node = VTOI(vp);
289: uint32_t lb_size, from, sectors;
290: int error;
291:
292: DPRINTF(STRATEGY, ("udf_strategy called\n"));
293:
294: /* check if we ought to be here */
295: if (vp->v_type == VBLK || vp->v_type == VCHR)
296: panic("udf_strategy: spec");
297:
298: /* only filebuffers ought to be read by this, no descriptors */
299: assert(bp->b_blkno >= 0);
300:
301: /* get sector size */
302: lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
303:
304: /* calculate sector to start from */
305: from = bp->b_blkno;
306:
307: /* calculate length to fetch/store in sectors */
308: sectors = bp->b_bcount / lb_size;
309: assert(bp->b_bcount > 0);
310:
1.3 snj 311: /* NEVER assume later that this buffer is already translated */
1.1 reinoud 312: /* bp->b_lblkno = bp->b_blkno; */
313:
314: DPRINTF(STRATEGY, ("\tread vp %p buf %p (blk no %"PRIu64")"
315: ", sector %d for %d sectors\n",
316: vp, bp, bp->b_blkno, from, sectors));
317:
1.10 msaitoh 318: /* check assertions: we OUGHT to always get multiples of this */
1.1 reinoud 319: assert(sectors * lb_size == bp->b_bcount);
320:
321: /* determine mode */
322: error = 0;
323: if (bp->b_flags & B_READ) {
324: /* read buffer from the udf_node, translate vtop on the way*/
325: udf_read_filebuf(udf_node, bp);
326: return bp->b_error;
1.6 christos 327: }
1.1 reinoud 328:
329: printf("udf_strategy: can't write yet\n");
330: return ENOTSUP;
331: }
332:
333: /* --------------------------------------------------------------------- */
334:
335: int
336: udf_readdir(void *v)
337: {
338: struct vop_readdir_args /* {
339: struct vnode *a_vp;
340: struct uio *a_uio;
1.5 elad 341: kauth_cred_t a_cred;
1.1 reinoud 342: int *a_eofflag;
343: off_t **a_cookies;
344: int *a_ncookies;
345: } */ *ap = v;
346: struct uio *uio = ap->a_uio;
347: struct vnode *vp = ap->a_vp;
348: struct udf_node *udf_node = VTOI(vp);
349: struct file_entry *fe;
350: struct extfile_entry *efe;
351: struct fileid_desc *fid;
1.10.8.1 matt 352: struct dirent *dirent;
1.1 reinoud 353: uint64_t file_size, diroffset, transoffset;
354: uint32_t lb_size;
355: int error;
356:
357: DPRINTF(READDIR, ("udf_readdir called\n"));
358:
359: /* This operation only makes sense on directory nodes. */
360: if (vp->v_type != VDIR)
361: return ENOTDIR;
362:
363: /* get directory filesize */
364: if (udf_node->fe) {
365: fe = udf_node->fe;
366: file_size = udf_rw64(fe->inf_len);
367: } else {
368: assert(udf_node->efe);
369: efe = udf_node->efe;
370: file_size = udf_rw64(efe->inf_len);
1.6 christos 371: }
1.1 reinoud 372:
1.10.8.1 matt 373: dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK | M_ZERO);
374:
1.1 reinoud 375: /*
376: * Add `.' pseudo entry if at offset zero since its not in the fid
377: * stream
378: */
379: if (uio->uio_offset == 0) {
380: DPRINTF(READDIR, ("\t'.' inserted\n"));
1.10.8.1 matt 381: strcpy(dirent->d_name, ".");
382: dirent->d_fileno = udf_calchash(&udf_node->loc);
383: dirent->d_type = DT_DIR;
384: dirent->d_namlen = strlen(dirent->d_name);
385: dirent->d_reclen = _DIRENT_SIZE(dirent);
386: uiomove(dirent, _DIRENT_SIZE(dirent), uio);
1.1 reinoud 387:
388: /* mark with magic value that we have done the dummy */
389: uio->uio_offset = UDF_DIRCOOKIE_DOT;
1.6 christos 390: }
1.1 reinoud 391:
392: /* we are called just as long as we keep on pushing data in */
393: error = 0;
394: if ((uio->uio_offset < file_size) &&
395: (uio->uio_resid >= sizeof(struct dirent))) {
396: /* allocate temporary space for fid */
397: lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
1.10.8.1 matt 398: fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
1.1 reinoud 399:
400: if (uio->uio_offset == UDF_DIRCOOKIE_DOT)
401: uio->uio_offset = 0;
402:
403: diroffset = uio->uio_offset;
404: transoffset = diroffset;
405: while (diroffset < file_size) {
406: DPRINTF(READDIR, ("\tread in fid stream\n"));
407: /* transfer a new fid/dirent */
408: error = udf_read_fid_stream(vp, &diroffset,
1.10.8.1 matt 409: fid, dirent);
1.1 reinoud 410: DPRINTFIF(READDIR, error, ("read error in read fid "
411: "stream : %d\n", error));
412: if (error)
413: break;
414:
415: /*
416: * If there isn't enough space in the uio to return a
417: * whole dirent, break off read
418: */
1.10.8.1 matt 419: if (uio->uio_resid < _DIRENT_SIZE(dirent))
1.1 reinoud 420: break;
421:
422: /* remember the last entry we transfered */
423: transoffset = diroffset;
424:
425: /* skip deleted entries */
426: if (fid->file_char & UDF_FILE_CHAR_DEL)
427: continue;
428:
429: /* skip not visible files */
430: if (fid->file_char & UDF_FILE_CHAR_VIS)
431: continue;
432:
433: /* copy dirent to the caller */
434: DPRINTF(READDIR, ("\tread dirent `%s', type %d\n",
1.10.8.1 matt 435: dirent->d_name, dirent->d_type));
436: uiomove(dirent, _DIRENT_SIZE(dirent), uio);
1.6 christos 437: }
1.1 reinoud 438:
439: /* pass on last transfered offset */
440: uio->uio_offset = transoffset;
1.10.8.1 matt 441: free(fid, M_UDFTEMP);
1.6 christos 442: }
1.1 reinoud 443:
444: if (ap->a_eofflag)
445: *ap->a_eofflag = (uio->uio_offset == file_size);
446:
447: #ifdef DEBUG
448: if (udf_verbose & UDF_DEBUG_READDIR) {
449: printf("returning offset %d\n", (uint32_t) uio->uio_offset);
450: if (ap->a_eofflag)
451: printf("returning EOF ? %d\n", *ap->a_eofflag);
452: if (error)
453: printf("readdir returning error %d\n", error);
1.6 christos 454: }
1.1 reinoud 455: #endif
456:
1.10.8.1 matt 457: free(dirent, M_UDFTEMP);
1.1 reinoud 458: return error;
459: }
460:
461: /* --------------------------------------------------------------------- */
462:
463: int
464: udf_lookup(void *v)
465: {
466: struct vop_lookup_args /* {
467: struct vnode *a_dvp;
468: struct vnode **a_vpp;
469: struct componentname *a_cnp;
470: } */ *ap = v;
471: struct vnode *dvp = ap->a_dvp;
472: struct vnode **vpp = ap->a_vpp;
473: struct componentname *cnp = ap->a_cnp;
474: struct udf_node *dir_node, *res_node;
475: struct udf_mount *ump;
476: struct long_ad icb_loc;
477: const char *name;
1.8 chs 478: int namelen, nameiop, islastcn, mounted_ro;
1.1 reinoud 479: int vnodetp;
480: int error, found;
481:
482: dir_node = VTOI(dvp);
483: ump = dir_node->ump;
484: *vpp = NULL;
485:
486: DPRINTF(LOOKUP, ("udf_lookup called\n"));
487:
488: /* simplify/clarification flags */
489: nameiop = cnp->cn_nameiop;
490: islastcn = cnp->cn_flags & ISLASTCN;
491: mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY;
492:
493: /* check exec/dirread permissions first */
1.10.8.2! matt 494: error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
1.1 reinoud 495: if (error)
496: return error;
497:
498: DPRINTF(LOOKUP, ("\taccess ok\n"));
499:
500: /*
501: * If requesting a modify on the last path element on a read-only
502: * filingsystem, reject lookup; XXX why is this repeated in every FS ?
503: */
504: if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME))
505: return EROFS;
506:
507: DPRINTF(LOOKUP, ("\tlooking up cnp->cn_nameptr '%s'\n",
508: cnp->cn_nameptr));
509: /* look in the nami cache; returns 0 on success!! */
510: error = cache_lookup(dvp, vpp, cnp);
511: if (error >= 0)
512: return error;
513:
514: DPRINTF(LOOKUP, ("\tNOT found in cache\n"));
515:
516: /*
517: * Obviously, the file is not (anymore) in the namecache, we have to
518: * search for it. There are three basic cases: '.', '..' and others.
519: *
520: * Following the guidelines of VOP_LOOKUP manpage and tmpfs.
521: */
522: error = 0;
523: if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) {
524: DPRINTF(LOOKUP, ("\tlookup '.'\n"));
525: /* special case 1 '.' */
526: VREF(dvp);
527: *vpp = dvp;
528: /* done */
529: } else if (cnp->cn_flags & ISDOTDOT) {
530: /* special case 2 '..' */
531: DPRINTF(LOOKUP, ("\tlookup '..'\n"));
532:
533: /* first unlock parent */
534: VOP_UNLOCK(dvp, 0);
535:
536: /* get our node */
537: name = "..";
538: namelen = 2;
539: found = udf_lookup_name_in_dir(dvp, name, namelen, &icb_loc);
540: if (!found)
541: error = ENOENT;
542:
543: if (!error) {
544: DPRINTF(LOOKUP, ("\tfound '..'\n"));
545: /* try to create/reuse the node */
546: error = udf_get_node(ump, &icb_loc, &res_node);
547:
548: if (!error) {
549: DPRINTF(LOOKUP, ("\tnode retrieved/created OK\n"));
550: *vpp = res_node->vnode;
1.6 christos 551: }
552: }
1.1 reinoud 553:
1.8 chs 554: /* try to relock parent */
555: vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1.1 reinoud 556: } else {
557: DPRINTF(LOOKUP, ("\tlookup file\n"));
558: /* all other files */
559: /* lookup filename in the directory; location icb_loc */
560: name = cnp->cn_nameptr;
561: namelen = cnp->cn_namelen;
562: found = udf_lookup_name_in_dir(dvp, name, namelen, &icb_loc);
563: if (!found) {
564: DPRINTF(LOOKUP, ("\tNOT found\n"));
565: /*
566: * UGH, didn't find name. If we're creating or naming
567: * on the last name this is OK and we ought to return
568: * EJUSTRETURN if its allowed to be created.
569: */
570: error = ENOENT;
571: if (islastcn &&
572: (nameiop == CREATE || nameiop == RENAME))
573: error = 0;
574: if (!error) {
1.10.8.2! matt 575: error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
1.1 reinoud 576: if (!error) {
577: /* keep the component name */
578: cnp->cn_flags |= SAVENAME;
579: error = EJUSTRETURN;
1.6 christos 580: }
581: }
1.1 reinoud 582: /* done */
583: } else {
584: /* try to create/reuse the node */
585: error = udf_get_node(ump, &icb_loc, &res_node);
586: if (!error) {
587: /*
588: * If we are not at the last path component
589: * and found a non-directory or non-link entry
590: * (which may itself be pointing to a
591: * directory), raise an error.
592: */
593: vnodetp = res_node->vnode->v_type;
594: if ((vnodetp != VDIR) && (vnodetp != VLNK)) {
595: if (!islastcn)
596: error = ENOTDIR;
597: }
598:
1.6 christos 599: }
1.1 reinoud 600: if (!error) {
601: *vpp = res_node->vnode;
1.6 christos 602: }
603: }
1.1 reinoud 604: }
605:
606: /*
607: * Store result in the cache if requested. If we are creating a file,
608: * the file might not be found and thus putting it into the namecache
609: * might be seen as negative caching.
610: */
611: if (cnp->cn_flags & MAKEENTRY)
612: cache_enter(dvp, *vpp, cnp);
613:
614: DPRINTFIF(LOOKUP, error, ("udf_lookup returing error %d\n", error));
615:
616: return error;
617: }
618:
619: /* --------------------------------------------------------------------- */
620:
621: int
622: udf_getattr(void *v)
623: {
624: struct vop_getattr_args /* {
625: struct vnode *a_vp;
626: struct vattr *a_vap;
1.5 elad 627: kauth_cred_t a_cred;
1.1 reinoud 628: struct proc *a_p;
629: } */ *ap = v;
630: struct vnode *vp = ap->a_vp;
631: struct udf_node *udf_node = VTOI(vp);
632: struct udf_mount *ump = udf_node->ump;
633: struct vattr *vap = ap->a_vap;
634: struct file_entry *fe;
635: struct extfile_entry *efe;
636: struct timestamp *atime, *mtime, *attrtime;
637: uint32_t nlink;
638: uint64_t filesize, blkssize;
639: uid_t uid;
640: gid_t gid;
641:
642: DPRINTF(CALL, ("udf_getattr called\n"));
643:
644: /* get descriptor information */
645: if (udf_node->fe) {
646: fe = udf_node->fe;
647: nlink = udf_rw16(fe->link_cnt);
648: uid = (uid_t)udf_rw32(fe->uid);
649: gid = (gid_t)udf_rw32(fe->gid);
650: filesize = udf_rw64(fe->inf_len);
651: blkssize = udf_rw64(fe->logblks_rec);
652: atime = &fe->atime;
653: mtime = &fe->mtime;
654: attrtime = &fe->attrtime;
655: } else {
656: assert(udf_node->efe);
657: efe = udf_node->efe;
658: nlink = udf_rw16(efe->link_cnt);
659: uid = (uid_t)udf_rw32(efe->uid);
660: gid = (gid_t)udf_rw32(efe->gid);
661: filesize = udf_rw64(efe->inf_len); /* XXX or obj_size? */
662: blkssize = udf_rw64(efe->logblks_rec);
663: atime = &efe->atime;
664: mtime = &efe->mtime;
665: attrtime = &efe->attrtime;
1.6 christos 666: }
1.1 reinoud 667:
668: /* do the uid/gid translation game */
669: if ((uid == (uid_t) -1) && (gid == (gid_t) -1)) {
670: uid = ump->mount_args.anon_uid;
671: gid = ump->mount_args.anon_gid;
1.6 christos 672: }
1.1 reinoud 673:
674: /* fill in struct vattr with values from the node */
675: VATTR_NULL(vap);
676: vap->va_type = vp->v_type;
677: vap->va_mode = udf_getaccessmode(udf_node);
678: vap->va_nlink = nlink;
679: vap->va_uid = uid;
680: vap->va_gid = gid;
681: vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
682: vap->va_fileid = udf_calchash(&udf_node->loc); /* inode hash XXX */
683: vap->va_size = filesize;
684: vap->va_blocksize = udf_node->ump->discinfo.sector_size; /* wise? */
685:
686: /*
687: * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
688: * 1 to the link count if its a directory we're requested attributes
689: * of.
690: */
691: if (vap->va_type == VDIR)
692: vap->va_nlink++;
693:
694: /* access times */
695: udf_timestamp_to_timespec(ump, atime, &vap->va_atime);
696: udf_timestamp_to_timespec(ump, mtime, &vap->va_mtime);
697: udf_timestamp_to_timespec(ump, attrtime, &vap->va_ctime);
698:
699: vap->va_gen = 1; /* no multiple generations yes (!?) */
700: vap->va_flags = 0; /* no flags */
701: vap->va_rdev = udf_node->rdev;
1.9 reinoud 702: vap->va_bytes = blkssize * udf_node->ump->discinfo.sector_size;
1.1 reinoud 703: vap->va_filerev = 1; /* TODO file revision numbers? */
704: vap->va_vaflags = 0; /* TODO which va_vaflags? */
705:
706: return 0;
707: }
708:
709: /* --------------------------------------------------------------------- */
710:
711: int
712: udf_setattr(void *v)
713: {
714: struct vop_setattr_args /* {
715: struct vnode *a_vp;
716: struct vattr *a_vap;
1.5 elad 717: kauth_cred_t a_cred;
1.1 reinoud 718: struct proc *a_p;
719: } */ *ap = v;
720: struct vnode *vp = ap->a_vp;
721: struct udf_node *udf_node = VTOI(vp);
722: struct udf_mount *ump = udf_node->ump;
723: struct vattr *vap = ap->a_vap;
724: uid_t uid, nobody_uid;
725: gid_t gid, nobody_gid;
726:
727: /* shut up gcc for now */
728: ap = ap;
729: vp = vp;
1.4 mrg 730: uid = 0; /* XXX gcc */
731: gid = 0; /* XXX gcc */
1.1 reinoud 732: udf_node = udf_node;
733:
734: DPRINTF(NOTIMPL, ("udf_setattr called\n"));
735:
736: /*
737: * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to
738: * subtract 1 to the link count if its a directory we're setting
739: * attributes on. See getattr.
740: */
741: if (vap->va_type == VDIR)
742: vap->va_nlink--;
743:
744: /* do the uid/gid translation game */
745: nobody_uid = ump->mount_args.nobody_uid;
746: nobody_gid = ump->mount_args.nobody_gid;
747: if ((uid == nobody_uid) && (gid == nobody_gid)) {
748: uid = (uid_t) -1;
749: gid = (gid_t) -1;
1.6 christos 750: }
1.1 reinoud 751:
752: /* TODO implement setattr!! NOT IMPLEMENTED yet */
753: return 0;
754: }
755:
756: /* --------------------------------------------------------------------- */
757:
758: /*
759: * Return POSIX pathconf information for UDF file systems.
760: */
761: int
762: udf_pathconf(void *v)
763: {
764: struct vop_pathconf_args /* {
765: struct vnode *a_vp;
766: int a_name;
767: register_t *a_retval;
768: } */ *ap = v;
769: struct vnode *vp = ap->a_vp;
770: struct udf_node *udf_node = VTOI(vp);
771: uint32_t bits;
772:
773: DPRINTF(CALL, ("udf_pathconf called\n"));
774:
775: switch (ap->a_name) {
776: case _PC_LINK_MAX:
777: *ap->a_retval = (1<<16)-1; /* 16 bits */
778: return 0;
779: case _PC_NAME_MAX:
780: *ap->a_retval = NAME_MAX;
781: return 0;
782: case _PC_PATH_MAX:
783: *ap->a_retval = PATH_MAX;
784: return 0;
785: case _PC_PIPE_BUF:
786: *ap->a_retval = PIPE_BUF;
787: return 0;
788: case _PC_CHOWN_RESTRICTED:
789: *ap->a_retval = 1;
790: return 0;
791: case _PC_NO_TRUNC:
792: *ap->a_retval = 1;
793: return 0;
794: case _PC_SYNC_IO:
795: *ap->a_retval = 0; /* synchronised is off for performance */
796: return 0;
797: case _PC_FILESIZEBITS:
798: bits = 32;
799: if (udf_node)
800: bits = 32 * vp->v_mount->mnt_dev_bshift;
801: *ap->a_retval = bits;
802: return 0;
1.6 christos 803: }
1.1 reinoud 804:
805: return EINVAL;
806: }
807:
808:
809: /* --------------------------------------------------------------------- */
810:
811: int
812: udf_open(void *v)
813: {
814: struct vop_open_args /* {
815: struct vnode *a_vp;
816: int a_mode;
1.5 elad 817: kauth_cred_t a_cred;
1.1 reinoud 818: struct proc *a_p;
1.7 christos 819: } */ *ap = v;
1.1 reinoud 820:
821: DPRINTF(CALL, ("udf_open called\n"));
1.4 mrg 822: ap = 0; /* XXX gcc */
1.1 reinoud 823:
824: return 0;
825: }
826:
827:
828: /* --------------------------------------------------------------------- */
829:
830: int
831: udf_close(void *v)
832: {
833: struct vop_close_args /* {
834: struct vnode *a_vp;
835: int a_fflag;
1.5 elad 836: kauth_cred_t a_cred;
1.1 reinoud 837: struct proc *a_p;
838: } */ *ap = v;
839: struct vnode *vp = ap->a_vp;
840: struct udf_node *udf_node = VTOI(vp);
841:
842: DPRINTF(CALL, ("udf_close called\n"));
843: udf_node = udf_node; /* shut up gcc */
844:
1.10.8.2! matt 845: mutex_enter(&vp->v_interlock);
1.1 reinoud 846: if (vp->v_usecount > 1) {
847: /* TODO update times */
1.6 christos 848: }
1.10.8.2! matt 849: mutex_exit(&vp->v_interlock);
1.1 reinoud 850:
851: return 0;
852: }
853:
854:
855: /* --------------------------------------------------------------------- */
856:
857: int
858: udf_access(void *v)
859: {
860: struct vop_access_args /* {
861: struct vnode *a_vp;
862: int a_mode;
1.5 elad 863: kauth_cred_t a_cred;
1.1 reinoud 864: struct proc *a_p;
865: } */ *ap = v;
866: struct vnode *vp = ap->a_vp;
867: mode_t mode = ap->a_mode;
1.5 elad 868: kauth_cred_t cred = ap->a_cred;
1.1 reinoud 869: struct udf_node *udf_node = VTOI(vp);
870: struct file_entry *fe;
871: struct extfile_entry *efe;
872: mode_t node_mode;
873: uid_t uid;
874: gid_t gid;
875:
876: DPRINTF(CALL, ("udf_access called\n"));
877:
878: /* get access mode to compare to */
879: node_mode = udf_getaccessmode(udf_node);
880:
881: /* get uid/gid pair */
882: if (udf_node->fe) {
883: fe = udf_node->fe;
884: uid = (uid_t)udf_rw32(fe->uid);
885: gid = (gid_t)udf_rw32(fe->gid);
886: } else {
887: assert(udf_node->efe);
888: efe = udf_node->efe;
889: uid = (uid_t)udf_rw32(efe->uid);
890: gid = (gid_t)udf_rw32(efe->gid);
1.6 christos 891: }
1.1 reinoud 892:
893: /* check if we are allowed to write */
894: switch (vp->v_type) {
895: case VDIR:
896: case VLNK:
897: case VREG:
898: /*
899: * normal nodes: check if we're on a read-only mounted
900: * filingsystem and bomb out if we're trying to write.
901: */
902: if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
903: return EROFS;
904: break;
905: case VBLK:
906: case VCHR:
907: case VSOCK:
908: case VFIFO:
909: /*
910: * special nodes: even on read-only mounted filingsystems
911: * these are allowed to be written to if permissions allow.
912: */
913: break;
914: default:
915: /* no idea what this is */
916: return EINVAL;
917: }
918:
919: /* TODO support for chflags checking i.e. IMMUTABLE flag */
920:
921: /* ask the generic vaccess to advice on security */
922: return vaccess(vp->v_type, node_mode, uid, gid, mode, cred);
923: }
924:
925: /* --------------------------------------------------------------------- */
926:
927: int
928: udf_create(void *v)
929: {
930: struct vop_create_args /* {
931: struct vnode *a_dvp;
932: struct vnode **a_vpp;
933: struct componentname *a_cnp;
934: struct vattr *a_vap;
935: } */ *ap = v;
936: struct componentname *cnp = ap->a_cnp;
937:
938: DPRINTF(NOTIMPL, ("udf_create called\n"));
939:
940: /* error out */
941: PNBUF_PUT(cnp->cn_pnbuf);
942: vput(ap->a_dvp);
943: return ENOTSUP;
944: }
945:
946: /* --------------------------------------------------------------------- */
947:
948: int
949: udf_mknod(void *v)
950: {
951: struct vop_mknod_args /* {
952: struct vnode *a_dvp;
953: struct vnode **a_vpp;
954: struct componentname *a_cnp;
955: struct vattr *a_vap;
956: } */ *ap = v;
957:
958: DPRINTF(NOTIMPL, ("udf_mknod called\n"));
959:
960: /* error out */
961: PNBUF_PUT(ap->a_cnp->cn_pnbuf);
962: vput(ap->a_dvp);
963: return ENOTSUP;
964: }
965:
966: /* --------------------------------------------------------------------- */
967:
968: int
969: udf_remove(void *v)
970: {
971: struct vop_remove_args /* {
972: struct vnode *a_dvp;
973: struct vnode *a_vp;
974: struct componentname *a_cnp;
975: } */ *ap = v;
976: struct vnode *dvp = ap->a_dvp;
977: struct vnode *vp = ap->a_vp;
978:
979: DPRINTF(NOTIMPL, ("udf_remove called\n"));
980:
981: /* error out */
982: vput(dvp);
983: vput(vp);
984:
985: return ENOTSUP;
986: }
987:
988: /* --------------------------------------------------------------------- */
989:
990: int
991: udf_link(void *v)
992: {
993: struct vop_link_args /* {
994: struct vnode *a_dvp;
995: struct vnode *a_vp;
996: struct componentname *a_cnp;
997: } */ *ap = v;
998: struct vnode *dvp = ap->a_dvp;
999: struct vnode *vp = ap->a_vp;
1000: struct componentname *cnp = ap->a_cnp;
1001:
1002: DPRINTF(NOTIMPL, ("udf_link called\n"));
1003:
1004: /* error out */
1005: /* XXX or just VOP_ABORTOP(dvp, a_cnp); ? */
1.10.8.1 matt 1006: if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
1.1 reinoud 1007: VOP_UNLOCK(vp, 0);
1008: PNBUF_PUT(cnp->cn_pnbuf);
1009: vput(dvp);
1010:
1011: return ENOTSUP;
1012: }
1013:
1014: /* --------------------------------------------------------------------- */
1015:
1016: int
1017: udf_symlink(void *v)
1018: {
1019: struct vop_symlink_args /* {
1020: struct vnode *a_dvp;
1021: struct vnode **a_vpp;
1022: struct componentname *a_cnp;
1023: struct vattr *a_vap;
1024: char *a_target;
1025: } */ *ap = v;
1026: struct vnode *dvp = ap->a_dvp;
1027: struct componentname *cnp = ap->a_cnp;
1028:
1029: DPRINTF(NOTIMPL, ("udf_symlink called\n"));
1030:
1031: /* error out */
1032: VOP_ABORTOP(dvp, cnp);
1033: vput(dvp);
1034:
1035: return ENOTSUP;
1036: }
1037:
1038: /* --------------------------------------------------------------------- */
1039:
1040: int
1041: udf_readlink(void *v)
1042: {
1043: struct vop_readlink_args /* {
1044: struct vnode *a_vp;
1045: struct uio *a_uio;
1.5 elad 1046: kauth_cred_t a_cred;
1.1 reinoud 1047: } */ *ap = v;
1048: #ifdef notyet
1049: struct vnode *vp = ap->a_vp;
1050: struct uio *uio = ap->a_uio;
1.5 elad 1051: kauth_cred_t cred = ap->a_cred;
1.1 reinoud 1052: #endif
1053:
1054: ap = ap; /* shut up gcc */
1055:
1056: DPRINTF(NOTIMPL, ("udf_readlink called\n"));
1057:
1058: /* TODO read `file' contents and process pathcomponents into a path */
1059: return ENOTSUP;
1060: }
1061:
1062: /* --------------------------------------------------------------------- */
1063:
1064: int
1065: udf_rename(void *v)
1066: {
1067: struct vop_rename_args /* {
1068: struct vnode *a_fdvp;
1069: struct vnode *a_fvp;
1070: struct componentname *a_fcnp;
1071: struct vnode *a_tdvp;
1072: struct vnode *a_tvp;
1073: struct componentname *a_tcnp;
1074: } */ *ap = v;
1075: struct vnode *tvp = ap->a_tvp;
1076: struct vnode *tdvp = ap->a_tdvp;
1077: struct vnode *fvp = ap->a_fvp;
1078: struct vnode *fdvp = ap->a_fdvp;
1079:
1080: DPRINTF(NOTIMPL, ("udf_rename called\n"));
1081:
1082: /* error out */
1083: if (tdvp == tvp)
1084: vrele(tdvp);
1085: else
1086: vput(tdvp);
1087: if (tvp != NULL)
1088: vput(tvp);
1089:
1090: /* release source nodes. */
1091: vrele(fdvp);
1092: vrele(fvp);
1093:
1094: return ENOTSUP;
1095: }
1096:
1097: /* --------------------------------------------------------------------- */
1098:
1099: int
1100: udf_mkdir(void *v)
1101: {
1102: struct vop_mkdir_args /* {
1103: struct vnode *a_dvp;
1104: struct vnode **a_vpp;
1105: struct componentname *a_cnp;
1106: struct vattr *a_vap;
1107: } */ *ap = v;
1108: struct vnode *dvp = ap->a_dvp;
1109: struct componentname *cnp = ap->a_cnp;
1110:
1111: DPRINTF(NOTIMPL, ("udf_mkdir called\n"));
1112:
1113: /* error out */
1114: PNBUF_PUT(cnp->cn_pnbuf);
1115: vput(dvp);
1116:
1117: return ENOTSUP;
1118: }
1119:
1120: /* --------------------------------------------------------------------- */
1121:
1122: int
1123: udf_rmdir(void *v)
1124: {
1125: struct vop_rmdir_args /* {
1126: struct vnode *a_dvp;
1127: struct vnode *a_vp;
1128: struct componentname *a_cnp;
1129: } */ *ap = v;
1130: struct vnode *vp = ap->a_vp;
1131: struct vnode *dvp = ap->a_dvp;
1132: struct componentname *cnp = ap->a_cnp;
1133: int error;
1134:
1135: cnp = cnp; /* shut up gcc */
1136:
1137: DPRINTF(NOTIMPL, ("udf_rmdir called\n"));
1138:
1139: error = ENOTSUP;
1140: /* error out */
1141: if (error != 0) {
1142: vput(dvp);
1143: vput(vp);
1144: }
1145:
1146: return error;
1147: }
1148:
1149: /* --------------------------------------------------------------------- */
1150:
1151: int
1152: udf_fsync(void *v)
1153: {
1154: struct vop_fsync_args /* {
1155: struct vnode *a_vp;
1.5 elad 1156: kauth_cred_t a_cred;
1.1 reinoud 1157: int a_flags;
1158: off_t offlo;
1159: off_t offhi;
1160: struct proc *a_p;
1161: } */ *ap = v;
1162: struct vnode *vp = ap->a_vp;
1163:
1164: DPRINTF(NOTIMPL, ("udf_fsync called\n"));
1165:
1166: vp = vp; /* shut up gcc */
1167:
1168: return 0;
1169: }
1170:
1171: /* --------------------------------------------------------------------- */
1172:
1173: int
1174: udf_advlock(void *v)
1175: {
1176: struct vop_advlock_args /* {
1177: struct vnode *a_vp;
1178: void *a_id;
1179: int a_op;
1180: struct flock *a_fl;
1181: int a_flags;
1182: } */ *ap = v;
1183: struct vnode *vp = ap->a_vp;
1184: struct udf_node *udf_node = VTOI(vp);
1185: struct file_entry *fe;
1186: struct extfile_entry *efe;
1187: uint64_t file_size;
1188:
1189: DPRINTF(LOCKING, ("udf_advlock called\n"));
1190:
1191: /* get directory filesize */
1192: if (udf_node->fe) {
1193: fe = udf_node->fe;
1194: file_size = udf_rw64(fe->inf_len);
1195: } else {
1196: assert(udf_node->efe);
1197: efe = udf_node->efe;
1198: file_size = udf_rw64(efe->inf_len);
1.6 christos 1199: }
1.1 reinoud 1200:
1201: return lf_advlock(ap, &udf_node->lockf, file_size);
1202: }
1203:
1204: /* --------------------------------------------------------------------- */
1205:
1206:
1207: /* Global vfs vnode data structures for udfs */
1208: int (**udf_vnodeop_p) __P((void *));
1209:
1210: const struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
1211: { &vop_default_desc, vn_default_error },
1212: { &vop_lookup_desc, udf_lookup }, /* lookup */
1213: { &vop_create_desc, udf_create }, /* create */ /* TODO */
1214: { &vop_mknod_desc, udf_mknod }, /* mknod */ /* TODO */
1215: { &vop_open_desc, udf_open }, /* open */
1216: { &vop_close_desc, udf_close }, /* close */
1217: { &vop_access_desc, udf_access }, /* access */
1218: { &vop_getattr_desc, udf_getattr }, /* getattr */
1219: { &vop_setattr_desc, udf_setattr }, /* setattr */ /* TODO */
1220: { &vop_read_desc, udf_read }, /* read */
1221: { &vop_write_desc, udf_write }, /* write */ /* WRITE */
1222: { &vop_lease_desc, genfs_lease_check }, /* lease */ /* TODO? */
1223: { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ /* TODO? */
1224: { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ /* TODO? */
1225: { &vop_poll_desc, genfs_poll }, /* poll */ /* TODO/OK? */
1226: { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ /* ? */
1227: { &vop_revoke_desc, genfs_revoke }, /* revoke */ /* TODO? */
1228: { &vop_mmap_desc, genfs_mmap }, /* mmap */ /* OK? */
1229: { &vop_fsync_desc, udf_fsync }, /* fsync */ /* TODO */
1230: { &vop_seek_desc, genfs_seek }, /* seek */
1231: { &vop_remove_desc, udf_remove }, /* remove */ /* TODO */
1232: { &vop_link_desc, udf_link }, /* link */ /* TODO */
1233: { &vop_rename_desc, udf_rename }, /* rename */ /* TODO */
1234: { &vop_mkdir_desc, udf_mkdir }, /* mkdir */ /* TODO */
1235: { &vop_rmdir_desc, udf_rmdir }, /* rmdir */ /* TODO */
1236: { &vop_symlink_desc, udf_symlink }, /* symlink */ /* TODO */
1237: { &vop_readdir_desc, udf_readdir }, /* readdir */
1238: { &vop_readlink_desc, udf_readlink }, /* readlink */ /* TEST ME */
1239: { &vop_abortop_desc, genfs_abortop }, /* abortop */ /* TODO/OK? */
1240: { &vop_inactive_desc, udf_inactive }, /* inactive */
1241: { &vop_reclaim_desc, udf_reclaim }, /* reclaim */
1242: { &vop_lock_desc, genfs_lock }, /* lock */
1243: { &vop_unlock_desc, genfs_unlock }, /* unlock */
1244: { &vop_bmap_desc, udf_trivial_bmap }, /* bmap */ /* 1:1 bmap */
1245: { &vop_strategy_desc, udf_strategy }, /* strategy */
1246: /* { &vop_print_desc, udf_print }, */ /* print */
1247: { &vop_islocked_desc, genfs_islocked }, /* islocked */
1248: { &vop_pathconf_desc, udf_pathconf }, /* pathconf */
1249: { &vop_advlock_desc, udf_advlock }, /* advlock */ /* TEST ME */
1250: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ /* ->strategy */
1251: { &vop_getpages_desc, genfs_getpages }, /* getpages */
1252: { &vop_putpages_desc, genfs_putpages }, /* putpages */
1253: { NULL, NULL }
1254: };
1255:
1256:
1257: const struct vnodeopv_desc udf_vnodeop_opv_desc = {
1258: &udf_vnodeop_p, udf_vnodeop_entries
1259: };
1260:
CVSweb <webmaster@jp.NetBSD.org>