1 /* $NetBSD: udf_vnops.c,v 1.101 2015/04/20 23:03:08 riastradh Exp $ */
4 * Copyright (c) 2006, 2008 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * Generic parts are derived from software contributed to The NetBSD Foundation
28 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
33 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.101 2015/04/20 23:03:08 riastradh Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/namei.h>
42 #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
43 #include <sys/kernel.h>
44 #include <sys/file.h> /* define FWRITE ... */
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/signalvar.h>
51 #include <sys/malloc.h>
52 #include <sys/dirent.h>
53 #include <sys/lockf.h>
54 #include <sys/kauth.h>
56 #include <miscfs/genfs/genfs.h>
57 #include <uvm/uvm_extern.h>
59 #include <fs/udf/ecma167-udf.h>
60 #include <fs/udf/udf_mount.h>
61 #include <sys/dirhash.h>
65 #include "udf_bswap.h"
68 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
70 /* forward declarations */
71 static int udf_do_readlink(struct udf_node
*udf_node
, uint64_t filesize
,
72 uint8_t *targetbuf
, int *length
);
77 /* implementations of vnode functions; table follows at end */
78 /* --------------------------------------------------------------------- */
83 struct vop_inactive_args
/* {
87 struct vnode
*vp
= ap
->a_vp
;
88 struct udf_node
*udf_node
= VTOI(vp
);
91 DPRINTF(NODE
, ("udf_inactive called for udf_node %p\n", VTOI(vp
)));
93 if (udf_node
== NULL
) {
94 DPRINTF(NODE
, ("udf_inactive: inactive NULL UDF node\n"));
100 * Optionally flush metadata to disc.
103 refcnt
= udf_rw16(udf_node
->fe
->link_cnt
);
105 assert(udf_node
->efe
);
106 refcnt
= udf_rw16(udf_node
->efe
->link_cnt
);
109 if ((refcnt
== 0) && (vp
->v_vflag
& VV_SYSTEM
)) {
110 DPRINTF(VOLUMES
, ("UDF_INACTIVE deleting VV_SYSTEM\n"));
111 /* system nodes are not writen out on inactive, so flush */
112 udf_node
->i_flags
= 0;
115 *ap
->a_recycle
= false;
116 if ((refcnt
== 0) && ((vp
->v_vflag
& VV_SYSTEM
) == 0)) {
117 *ap
->a_recycle
= true;
122 /* write out its node */
123 if (udf_node
->i_flags
& (IN_CHANGE
| IN_UPDATE
| IN_MODIFIED
))
124 udf_update(vp
, NULL
, NULL
, NULL
, 0);
130 /* --------------------------------------------------------------------- */
135 struct vop_reclaim_args
/* {
138 struct vnode
*vp
= ap
->a_vp
;
139 struct udf_node
*udf_node
= VTOI(vp
);
142 DPRINTF(NODE
, ("udf_reclaim called for node %p\n", udf_node
));
143 if (prtactive
&& vp
->v_usecount
> 1)
144 vprint("udf_reclaim(): pushing active", vp
);
146 if (udf_node
== NULL
) {
147 DPRINTF(NODE
, ("udf_reclaim(): null udfnode\n"));
152 * If the file has not been referenced anymore in a directory
153 * we ought to free up the resources on disc if applicable.
156 refcnt
= udf_rw16(udf_node
->fe
->link_cnt
);
158 assert(udf_node
->efe
);
159 refcnt
= udf_rw16(udf_node
->efe
->link_cnt
);
162 if ((refcnt
== 0) && ((vp
->v_vflag
& VV_SYSTEM
) == 0)) {
163 /* remove this file's allocation */
164 DPRINTF(NODE
, ("udf_inactive deleting unlinked file\n"));
165 udf_delete_node(udf_node
);
168 /* update note for closure */
169 udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_CLOSE
);
171 /* async check to see if all node descriptors are written out */
172 while ((volatile int) udf_node
->outstanding_nodedscr
> 0) {
173 vprint("udf_reclaim(): waiting for writeout\n", vp
);
174 tsleep(&udf_node
->outstanding_nodedscr
, PRIBIO
, "recl wait", hz
/8);
177 vcache_remove(vp
->v_mount
, &udf_node
->loc
.loc
,
178 sizeof(udf_node
->loc
.loc
));
180 /* dispose all node knowledge */
181 udf_dispose_node(udf_node
);
186 /* --------------------------------------------------------------------- */
191 struct vop_read_args
/* {
197 struct vnode
*vp
= ap
->a_vp
;
198 struct uio
*uio
= ap
->a_uio
;
199 int ioflag
= ap
->a_ioflag
;
200 int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
201 struct uvm_object
*uobj
;
202 struct udf_node
*udf_node
= VTOI(vp
);
203 struct file_entry
*fe
;
204 struct extfile_entry
*efe
;
210 * XXX reading from extended attributes not yet implemented. FreeBSD
211 * has it in mind to forward the IO_EXT read call to the
215 DPRINTF(READ
, ("udf_read called\n"));
217 /* can this happen? some filingsystems have this check */
218 if (uio
->uio_offset
< 0)
220 if (uio
->uio_resid
== 0)
223 /* protect against rogue programs reading raw directories and links */
224 if ((ioflag
& IO_ALTSEMANTICS
) == 0) {
225 if (vp
->v_type
== VDIR
)
227 /* all but regular files just give EINVAL */
228 if (vp
->v_type
!= VREG
)
233 assert(udf_node
->fe
|| udf_node
->efe
);
235 /* get file/directory filesize */
238 file_size
= udf_rw64(fe
->inf_len
);
240 assert(udf_node
->efe
);
242 file_size
= udf_rw64(efe
->inf_len
);
245 /* read contents using buffercache */
248 while (uio
->uio_resid
> 0) {
250 if (file_size
<= uio
->uio_offset
)
253 /* maximise length to file extremity */
254 len
= MIN(file_size
- uio
->uio_offset
, uio
->uio_resid
);
258 /* ubc, here we come, prepare to trap */
259 error
= ubc_uiomove(uobj
, uio
, len
, advice
,
260 UBC_READ
| UBC_PARTIALOK
| UBC_UNMAP_FLAG(vp
));
265 /* note access time unless not requested */
266 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
)) {
267 udf_node
->i_flags
|= IN_ACCESS
;
268 if ((ioflag
& IO_SYNC
) == IO_SYNC
) {
271 uerror
= udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_WAIT
);
280 /* --------------------------------------------------------------------- */
285 struct vop_write_args
/* {
291 struct vnode
*vp
= ap
->a_vp
;
292 struct uio
*uio
= ap
->a_uio
;
293 int ioflag
= ap
->a_ioflag
;
294 kauth_cred_t cred
= ap
->a_cred
;
295 int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
296 struct uvm_object
*uobj
;
297 struct udf_node
*udf_node
= VTOI(vp
);
298 struct file_entry
*fe
;
299 struct extfile_entry
*efe
;
300 uint64_t file_size
, old_size
, old_offset
;
302 int aflag
= ioflag
& IO_SYNC
? B_SYNC
: 0;
307 * XXX writing to extended attributes not yet implemented. FreeBSD has
308 * it in mind to forward the IO_EXT read call to the
312 DPRINTF(WRITE
, ("udf_write called\n"));
314 /* can this happen? some filingsystems have this check */
315 if (uio
->uio_offset
< 0)
317 if (uio
->uio_resid
== 0)
320 /* protect against rogue programs writing raw directories or links */
321 if ((ioflag
& IO_ALTSEMANTICS
) == 0) {
322 if (vp
->v_type
== VDIR
)
324 /* all but regular files just give EINVAL for now */
325 if (vp
->v_type
!= VREG
)
330 assert(udf_node
->fe
|| udf_node
->efe
);
332 /* get file/directory filesize */
335 file_size
= udf_rw64(fe
->inf_len
);
337 assert(udf_node
->efe
);
339 file_size
= udf_rw64(efe
->inf_len
);
341 old_size
= file_size
;
343 /* if explicitly asked to append, uio_offset can be wrong? */
344 if (ioflag
& IO_APPEND
)
345 uio
->uio_offset
= file_size
;
347 extended
= (uio
->uio_offset
+ uio
->uio_resid
> file_size
);
349 DPRINTF(WRITE
, ("extending file from %"PRIu64
" to %"PRIu64
"\n",
350 file_size
, uio
->uio_offset
+ uio
->uio_resid
));
351 error
= udf_grow_node(udf_node
, uio
->uio_offset
+ uio
->uio_resid
);
354 file_size
= uio
->uio_offset
+ uio
->uio_resid
;
357 /* write contents using buffercache */
359 resid
= uio
->uio_resid
;
362 uvm_vnp_setwritesize(vp
, file_size
);
363 old_offset
= uio
->uio_offset
;
364 while (uio
->uio_resid
> 0) {
365 /* maximise length to file extremity */
366 len
= MIN(file_size
- uio
->uio_offset
, uio
->uio_resid
);
370 genfs_node_wrlock(vp
);
371 error
= GOP_ALLOC(vp
, uio
->uio_offset
, len
, aflag
, cred
);
372 genfs_node_unlock(vp
);
376 /* ubc, here we come, prepare to trap */
377 error
= ubc_uiomove(uobj
, uio
, len
, advice
,
378 UBC_WRITE
| UBC_UNMAP_FLAG(vp
));
383 * flush what we just wrote if necessary.
384 * XXXUBC simplistic async flushing.
386 * Directories are excluded since its file data that we want
389 if ((vp
->v_type
!= VDIR
) &&
390 (old_offset
>> 16 != uio
->uio_offset
>> 16)) {
391 mutex_enter(vp
->v_interlock
);
392 error
= VOP_PUTPAGES(vp
, (old_offset
>> 16) << 16,
393 (uio
->uio_offset
>> 16) << 16,
394 PGO_CLEANIT
| PGO_LAZY
);
395 old_offset
= uio
->uio_offset
;
398 uvm_vnp_setsize(vp
, file_size
);
400 /* mark node changed and request update */
401 udf_node
->i_flags
|= IN_CHANGE
| IN_UPDATE
;
402 if (vp
->v_mount
->mnt_flag
& MNT_RELATIME
)
403 udf_node
->i_flags
|= IN_ACCESS
;
406 * XXX TODO FFS has code here to reset setuid & setgid when we're not
407 * the superuser as a precaution against tampering.
410 /* if we wrote a thing, note write action on vnode */
411 if (resid
> uio
->uio_resid
)
412 VN_KNOTE(vp
, NOTE_WRITE
| (extended
? NOTE_EXTEND
: 0));
415 /* bring back file size to its former size */
416 /* take notice of its errors? */
417 (void) udf_chsize(vp
, (u_quad_t
) old_size
, cred
);
420 uio
->uio_offset
-= resid
- uio
->uio_resid
;
421 uio
->uio_resid
= resid
;
423 /* if we write and we're synchronous, update node */
424 if ((resid
> uio
->uio_resid
) && ((ioflag
& IO_SYNC
) == IO_SYNC
))
425 error
= udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_WAIT
);
432 /* --------------------------------------------------------------------- */
435 * `Special' bmap functionality that translates all incomming requests to
436 * translate to vop_strategy() calls with the same blocknumbers effectively
437 * not translating at all.
441 udf_trivial_bmap(void *v
)
443 struct vop_bmap_args
/* {
446 struct vnode **a_vpp;
450 struct vnode
*vp
= ap
->a_vp
; /* our node */
451 struct vnode
**vpp
= ap
->a_vpp
; /* return node */
452 daddr_t
*bnp
= ap
->a_bnp
; /* translated */
453 daddr_t bn
= ap
->a_bn
; /* origional */
454 int *runp
= ap
->a_runp
;
455 struct udf_node
*udf_node
= VTOI(vp
);
458 /* get logical block size */
459 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
461 /* could return `-1' to indicate holes/zeros */
465 /* set the vnode to read the data from with strategy on itself */
469 /* set runlength of maximum block size */
471 *runp
= MAXPHYS
/ lb_size
; /* or with -1 ? */
477 /* --------------------------------------------------------------------- */
480 udf_vfsstrategy(void *v
)
482 struct vop_strategy_args
/* {
486 struct vnode
*vp
= ap
->a_vp
;
487 struct buf
*bp
= ap
->a_bp
;
488 struct udf_node
*udf_node
= VTOI(vp
);
489 uint32_t lb_size
, sectors
;
491 DPRINTF(STRATEGY
, ("udf_strategy called\n"));
493 /* check if we ought to be here */
494 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
495 panic("udf_strategy: spec");
497 /* only filebuffers ought to be read/write by this, no descriptors */
498 assert(bp
->b_blkno
>= 0);
500 /* get sector size */
501 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
503 /* calculate length to fetch/store in sectors */
504 sectors
= bp
->b_bcount
/ lb_size
;
505 assert(bp
->b_bcount
> 0);
507 /* NEVER assume later that this buffer is already translated */
508 /* bp->b_lblkno = bp->b_blkno; */
510 /* check assertions: we OUGHT to always get multiples of this */
511 assert(sectors
* lb_size
== bp
->b_bcount
);
515 if (bp
->b_flags
& B_READ
) {
516 DPRINTF(STRATEGY
, ("\tread vp %p buf %p (blk no %"PRIu64
")"
517 ", for %d sectors\n",
518 vp
, bp
, bp
->b_blkno
, sectors
));
520 /* read buffer from the udf_node, translate vtop on the way*/
521 udf_read_filebuf(udf_node
, bp
);
523 DPRINTF(STRATEGY
, ("\twrite vp %p buf %p (blk no %"PRIu64
")"
524 ", for %d sectors\n",
525 vp
, bp
, bp
->b_blkno
, sectors
));
527 /* write buffer to the udf_node, translate vtop on the way*/
528 udf_write_filebuf(udf_node
, bp
);
534 /* --------------------------------------------------------------------- */
539 struct vop_readdir_args
/* {
547 struct uio
*uio
= ap
->a_uio
;
548 struct vnode
*vp
= ap
->a_vp
;
549 struct udf_node
*udf_node
= VTOI(vp
);
550 struct file_entry
*fe
;
551 struct extfile_entry
*efe
;
552 struct fileid_desc
*fid
;
553 struct dirent
*dirent
;
554 uint64_t file_size
, diroffset
, transoffset
;
558 DPRINTF(READDIR
, ("udf_readdir called\n"));
560 /* This operation only makes sense on directory nodes. */
561 if (vp
->v_type
!= VDIR
)
564 /* get directory filesize */
567 file_size
= udf_rw64(fe
->inf_len
);
569 assert(udf_node
->efe
);
571 file_size
= udf_rw64(efe
->inf_len
);
574 dirent
= malloc(sizeof(struct dirent
), M_UDFTEMP
, M_WAITOK
| M_ZERO
);
577 * Add `.' pseudo entry if at offset zero since its not in the fid
580 if (uio
->uio_offset
== 0) {
581 DPRINTF(READDIR
, ("\t'.' inserted\n"));
582 strcpy(dirent
->d_name
, ".");
583 dirent
->d_fileno
= udf_get_node_id(&udf_node
->loc
);
584 dirent
->d_type
= DT_DIR
;
585 dirent
->d_namlen
= strlen(dirent
->d_name
);
586 dirent
->d_reclen
= _DIRENT_SIZE(dirent
);
587 uiomove(dirent
, _DIRENT_SIZE(dirent
), uio
);
589 /* mark with magic value that we have done the dummy */
590 uio
->uio_offset
= UDF_DIRCOOKIE_DOT
;
593 /* we are called just as long as we keep on pushing data in */
595 if (uio
->uio_offset
< file_size
) {
596 /* allocate temporary space for fid */
597 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
598 fid
= malloc(lb_size
, M_UDFTEMP
, M_WAITOK
);
600 if (uio
->uio_offset
== UDF_DIRCOOKIE_DOT
)
603 diroffset
= uio
->uio_offset
;
604 transoffset
= diroffset
;
605 while (diroffset
< file_size
) {
606 DPRINTF(READDIR
, ("\tread in fid stream\n"));
607 /* transfer a new fid/dirent */
608 error
= udf_read_fid_stream(vp
, &diroffset
, fid
, dirent
);
609 DPRINTFIF(READDIR
, error
, ("read error in read fid "
610 "stream : %d\n", error
));
615 * If there isn't enough space in the uio to return a
616 * whole dirent, break off read
618 if (uio
->uio_resid
< _DIRENT_SIZE(dirent
))
621 /* remember the last entry we transfered */
622 transoffset
= diroffset
;
624 /* skip deleted entries */
625 if (fid
->file_char
& UDF_FILE_CHAR_DEL
)
628 /* skip not visible files */
629 if (fid
->file_char
& UDF_FILE_CHAR_VIS
)
632 /* copy dirent to the caller */
633 DPRINTF(READDIR
, ("\tread dirent `%s', type %d\n",
634 dirent
->d_name
, dirent
->d_type
));
635 uiomove(dirent
, _DIRENT_SIZE(dirent
), uio
);
638 /* pass on last transfered offset */
639 uio
->uio_offset
= transoffset
;
640 free(fid
, M_UDFTEMP
);
644 *ap
->a_eofflag
= (uio
->uio_offset
>= file_size
);
647 if (udf_verbose
& UDF_DEBUG_READDIR
) {
648 printf("returning offset %d\n", (uint32_t) uio
->uio_offset
);
650 printf("returning EOF ? %d\n", *ap
->a_eofflag
);
652 printf("readdir returning error %d\n", error
);
656 free(dirent
, M_UDFTEMP
);
660 /* --------------------------------------------------------------------- */
665 struct vop_lookup_v2_args
/* {
667 struct vnode **a_vpp;
668 struct componentname *a_cnp;
670 struct vnode
*dvp
= ap
->a_dvp
;
671 struct vnode
**vpp
= ap
->a_vpp
;
672 struct componentname
*cnp
= ap
->a_cnp
;
673 struct udf_node
*dir_node
, *res_node
;
674 struct udf_mount
*ump
;
675 struct long_ad icb_loc
;
680 int namelen
, nameiop
, islastcn
, mounted_ro
;
683 dir_node
= VTOI(dvp
);
687 DPRINTF(LOOKUP
, ("udf_lookup called, lookup `%s`\n",
690 /* simplify/clarification flags */
691 nameiop
= cnp
->cn_nameiop
;
692 islastcn
= cnp
->cn_flags
& ISLASTCN
;
693 mounted_ro
= dvp
->v_mount
->mnt_flag
& MNT_RDONLY
;
695 /* check exec/dirread permissions first */
696 error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
);
700 DPRINTF(LOOKUP
, ("\taccess ok\n"));
703 * If requesting a modify on the last path element on a read-only
704 * filingsystem, reject lookup; XXX why is this repeated in every FS ?
706 if (islastcn
&& mounted_ro
&& (nameiop
== DELETE
|| nameiop
== RENAME
))
709 DPRINTF(LOOKUP
, ("\tlooking up cnp->cn_nameptr '%s'\n",
711 /* look in the namecache */
712 if (cache_lookup(dvp
, cnp
->cn_nameptr
, cnp
->cn_namelen
,
713 cnp
->cn_nameiop
, cnp
->cn_flags
, NULL
, vpp
)) {
714 return *vpp
== NULLVP
? ENOENT
: 0;
717 DPRINTF(LOOKUP
, ("\tNOT found in cache\n"));
720 * Obviously, the file is not (anymore) in the namecache, we have to
721 * search for it. There are three basic cases: '.', '..' and others.
723 * Following the guidelines of VOP_LOOKUP manpage and tmpfs.
726 if ((cnp
->cn_namelen
== 1) && (cnp
->cn_nameptr
[0] == '.')) {
727 DPRINTF(LOOKUP
, ("\tlookup '.'\n"));
728 /* special case 1 '.' */
729 if (islastcn
&& cnp
->cn_nameiop
== RENAME
) {
737 } else if (cnp
->cn_flags
& ISDOTDOT
) {
738 /* special case 2 '..' */
739 DPRINTF(LOOKUP
, ("\tlookup '..'\n"));
741 if (islastcn
&& cnp
->cn_nameiop
== RENAME
) {
749 error
= udf_lookup_name_in_dir(dvp
, name
, namelen
,
756 /* first unlock parent */
760 DPRINTF(LOOKUP
, ("\tfound '..'\n"));
761 /* try to create/reuse the node */
762 error
= udf_get_node(ump
, &icb_loc
, &res_node
);
766 ("\tnode retrieved/created OK\n"));
767 *vpp
= res_node
->vnode
;
771 /* try to relock parent */
772 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
776 /* all other files */
777 DPRINTF(LOOKUP
, ("\tlookup file/dir in directory\n"));
779 /* lookup filename in the directory; location icb_loc */
780 name
= cnp
->cn_nameptr
;
781 namelen
= cnp
->cn_namelen
;
782 error
= udf_lookup_name_in_dir(dvp
, name
, namelen
,
787 DPRINTF(LOOKUP
, ("\tNOT found\n"));
789 * The entry was not found in the directory. This is
790 * valid if we are creating or renaming an entry and
791 * are working on the last component of the path name.
793 if (islastcn
&& (cnp
->cn_nameiop
== CREATE
||
794 cnp
->cn_nameiop
== RENAME
)) {
795 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
);
808 * XXX NOTE tmpfs has a test here that tests that intermediate
809 * components i.e. not the last one ought to be either a directory or
810 * a link. It seems to function well without this code.
813 /* try to create/reuse the node */
814 error
= udf_get_node(ump
, &icb_loc
, &res_node
);
818 /* check permissions */
819 if (islastcn
&& (cnp
->cn_nameiop
== DELETE
||
820 cnp
->cn_nameiop
== RENAME
) ) {
821 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
);
823 vput(res_node
->vnode
);
828 * Check if the directory has its sticky bit set. If so, ask
829 * for clearance since only the owner of a file or directory
830 * can remove/rename from taht directory.
832 mode
= udf_getaccessmode(dir_node
);
833 if ((mode
& S_ISTXT
) != 0) {
834 udf_getownership(dir_node
, &d_uid
, &d_gid
);
835 error
= kauth_authorize_vnode(cnp
->cn_cred
,
836 KAUTH_VNODE_DELETE
, res_node
->vnode
,
837 dir_node
->vnode
, genfs_can_sticky(cnp
->cn_cred
,
841 vput(res_node
->vnode
);
847 *vpp
= res_node
->vnode
;
851 * Store result in the cache if requested. If we are creating a file,
852 * the file might not be found and thus putting it into the namecache
853 * might be seen as negative caching.
855 if (nameiop
!= CREATE
)
856 cache_enter(dvp
, *vpp
, cnp
->cn_nameptr
, cnp
->cn_namelen
,
860 if (error
== 0 && *vpp
!= dvp
)
862 DPRINTFIF(LOOKUP
, error
, ("udf_lookup returing error %d\n", error
));
867 /* --------------------------------------------------------------------- */
872 struct vop_getattr_args
/* {
878 struct vnode
*vp
= ap
->a_vp
;
879 struct udf_node
*udf_node
= VTOI(vp
);
880 struct udf_mount
*ump
= udf_node
->ump
;
881 struct file_entry
*fe
= udf_node
->fe
;
882 struct extfile_entry
*efe
= udf_node
->efe
;
883 struct filetimes_extattr_entry
*ft_extattr
;
884 struct device_extattr_entry
*devattr
;
885 struct vattr
*vap
= ap
->a_vap
;
886 struct timestamp
*atime
, *mtime
, *attrtime
, *creatime
;
887 uint64_t filesize
, blkssize
;
889 uint32_t offset
, a_l
;
890 uint8_t *filedata
, *targetbuf
;
895 DPRINTF(CALL
, ("udf_getattr called\n"));
897 /* update times before we returning values */
898 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
900 /* get descriptor information */
902 nlink
= udf_rw16(fe
->link_cnt
);
903 uid
= (uid_t
)udf_rw32(fe
->uid
);
904 gid
= (gid_t
)udf_rw32(fe
->gid
);
905 filesize
= udf_rw64(fe
->inf_len
);
906 blkssize
= udf_rw64(fe
->logblks_rec
);
909 attrtime
= &fe
->attrtime
;
915 /* check our extended attribute if present */
916 error
= udf_extattr_search_intern(udf_node
,
917 UDF_FILETIMES_ATTR_NO
, "", &offset
, &a_l
);
919 ft_extattr
= (struct filetimes_extattr_entry
*)
921 if (ft_extattr
->existence
& UDF_FILETIMES_FILE_CREATION
)
922 creatime
= &ft_extattr
->times
[0];
925 assert(udf_node
->efe
);
926 nlink
= udf_rw16(efe
->link_cnt
);
927 uid
= (uid_t
)udf_rw32(efe
->uid
);
928 gid
= (gid_t
)udf_rw32(efe
->gid
);
929 filesize
= udf_rw64(efe
->inf_len
); /* XXX or obj_size? */
930 blkssize
= udf_rw64(efe
->logblks_rec
);
933 attrtime
= &efe
->attrtime
;
934 creatime
= &efe
->ctime
;
935 filedata
= efe
->data
;
938 /* do the uid/gid translation game */
939 if (uid
== (uid_t
) -1)
940 uid
= ump
->mount_args
.anon_uid
;
941 if (gid
== (gid_t
) -1)
942 gid
= ump
->mount_args
.anon_gid
;
944 /* fill in struct vattr with values from the node */
946 vap
->va_type
= vp
->v_type
;
947 vap
->va_mode
= udf_getaccessmode(udf_node
);
948 vap
->va_nlink
= nlink
;
951 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsidx
.__fsid_val
[0];
952 vap
->va_fileid
= udf_get_node_id(&udf_node
->loc
); /* inode hash XXX */
953 vap
->va_size
= filesize
;
954 vap
->va_blocksize
= udf_node
->ump
->discinfo
.sector_size
; /* wise? */
957 * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
958 * 1 to the link count if its a directory we're requested attributes
961 if (vap
->va_type
== VDIR
)
965 * BUG-ALERT: Posix requires the va_size to be pathlength for symbolic
968 if (vap
->va_type
== VLNK
) {
969 /* claim temporary buffers for translation */
970 targetbuf
= malloc(PATH_MAX
+1, M_UDFTEMP
, M_WAITOK
);
971 error
= udf_do_readlink(udf_node
, filesize
, targetbuf
, &length
);
973 vap
->va_size
= length
;
974 KASSERT(length
== strlen(targetbuf
));
976 free(targetbuf
, M_UDFTEMP
);
977 /* XXX return error? */
981 udf_timestamp_to_timespec(ump
, atime
, &vap
->va_atime
);
982 udf_timestamp_to_timespec(ump
, mtime
, &vap
->va_mtime
);
983 udf_timestamp_to_timespec(ump
, attrtime
, &vap
->va_ctime
);
984 udf_timestamp_to_timespec(ump
, creatime
, &vap
->va_birthtime
);
986 vap
->va_gen
= 1; /* no multiple generations yes (!?) */
987 vap
->va_flags
= 0; /* no flags */
988 vap
->va_bytes
= blkssize
* udf_node
->ump
->discinfo
.sector_size
;
989 vap
->va_filerev
= 1; /* TODO file revision numbers? */
991 /* TODO get vaflags from the extended attributes? */
993 if ((vap
->va_type
== VBLK
) || (vap
->va_type
== VCHR
)) {
994 error
= udf_extattr_search_intern(udf_node
,
995 UDF_DEVICESPEC_ATTR_NO
, "",
997 /* if error, deny access */
998 if (error
|| (filedata
== NULL
)) {
999 vap
->va_mode
= 0; /* or v_type = VNON? */
1001 devattr
= (struct device_extattr_entry
*)
1003 vap
->va_rdev
= makedev(
1004 udf_rw32(devattr
->major
),
1005 udf_rw32(devattr
->minor
)
1007 /* TODO we could check the implementator */
1014 /* --------------------------------------------------------------------- */
1017 udf_chown(struct vnode
*vp
, uid_t new_uid
, gid_t new_gid
,
1020 struct udf_node
*udf_node
= VTOI(vp
);
1026 /* TODO get vaflags from the extended attributes? */
1027 /* Immutable or append-only files cannot be modified, either. */
1028 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
1032 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1035 /* retrieve old values */
1036 udf_getownership(udf_node
, &uid
, &gid
);
1038 /* only one could be specified */
1039 if (new_uid
== VNOVAL
)
1041 if (new_gid
== VNOVAL
)
1044 /* check if we can fit it in an 32 bits */
1045 if ((uid_t
) ((uint32_t) new_uid
) != new_uid
)
1047 if ((gid_t
) ((uint32_t) new_gid
) != new_gid
)
1050 /* check permissions */
1051 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_CHANGE_OWNERSHIP
,
1052 vp
, NULL
, genfs_can_chown(cred
, uid
, gid
, new_uid
, new_gid
));
1056 /* change the ownership */
1057 udf_setownership(udf_node
, new_uid
, new_gid
);
1059 /* mark node changed */
1060 udf_node
->i_flags
|= IN_CHANGE
;
1067 udf_chmod(struct vnode
*vp
, mode_t mode
, kauth_cred_t cred
)
1069 struct udf_node
*udf_node
= VTOI(vp
);
1075 /* TODO get vaflags from the extended attributes? */
1076 /* Immutable or append-only files cannot be modified, either. */
1077 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
1081 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1084 /* retrieve uid/gid values */
1085 udf_getownership(udf_node
, &uid
, &gid
);
1087 /* check permissions */
1088 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_SECURITY
, vp
,
1089 NULL
, genfs_can_chmod(vp
->v_type
, cred
, uid
, gid
, mode
));
1094 udf_setaccessmode(udf_node
, mode
);
1096 /* mark node changed */
1097 udf_node
->i_flags
|= IN_CHANGE
;
1105 udf_chsize(struct vnode
*vp
, u_quad_t newsize
, kauth_cred_t cred
)
1107 struct udf_node
*udf_node
= VTOI(vp
);
1108 int error
, extended
;
1110 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1113 /* Decide whether this is a valid operation based on the file type. */
1114 switch (vp
->v_type
) {
1118 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1126 /* Allow modifications of special files even if in the file
1127 * system is mounted read-only (we are not modifying the
1128 * files themselves, but the objects they represent). */
1131 /* Anything else is unsupported. */
1136 /* TODO get vaflags from the extended attributes? */
1137 /* Immutable or append-only files cannot be modified, either. */
1138 if (node
->flags
& (IMMUTABLE
| APPEND
))
1142 /* resize file to the requested size */
1143 error
= udf_resize_node(udf_node
, newsize
, &extended
);
1147 udf_node
->i_flags
|= IN_CHANGE
| IN_MODIFY
;
1148 if (vp
->v_mount
->mnt_flag
& MNT_RELATIME
)
1149 udf_node
->i_flags
|= IN_ACCESS
;
1150 VN_KNOTE(vp
, NOTE_ATTRIB
| (extended
? NOTE_EXTEND
: 0));
1151 udf_update(vp
, NULL
, NULL
, NULL
, 0);
1159 udf_chflags(struct vnode
*vp
, mode_t mode
, kauth_cred_t cred
)
1161 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1165 * XXX we can't do this yet, as its not described in the standard yet
1173 udf_chtimes(struct vnode
*vp
,
1174 struct timespec
*atime
, struct timespec
*mtime
,
1175 struct timespec
*birthtime
, int setattrflags
,
1178 struct udf_node
*udf_node
= VTOI(vp
);
1184 /* TODO get vaflags from the extended attributes? */
1185 /* Immutable or append-only files cannot be modified, either. */
1186 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
1190 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1193 /* retrieve uid/gid values */
1194 udf_getownership(udf_node
, &uid
, &gid
);
1196 /* check permissions */
1197 error
= kauth_authorize_vnode(cred
, KAUTH_VNODE_WRITE_TIMES
, vp
,
1198 NULL
, genfs_can_chtimes(vp
, setattrflags
, uid
, cred
));
1202 /* update node flags depending on what times are passed */
1203 if (atime
->tv_sec
!= VNOVAL
)
1204 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
))
1205 udf_node
->i_flags
|= IN_ACCESS
;
1206 if ((mtime
->tv_sec
!= VNOVAL
) || (birthtime
->tv_sec
!= VNOVAL
)) {
1207 udf_node
->i_flags
|= IN_CHANGE
| IN_UPDATE
;
1208 if (vp
->v_mount
->mnt_flag
& MNT_RELATIME
)
1209 udf_node
->i_flags
|= IN_ACCESS
;
1212 return udf_update(vp
, atime
, mtime
, birthtime
, 0);
1217 udf_setattr(void *v
)
1219 struct vop_setattr_args
/* {
1221 struct vattr *a_vap;
1222 kauth_cred_t a_cred;
1225 struct vnode
*vp
= ap
->a_vp
;
1226 /* struct udf_node *udf_node = VTOI(vp); */
1227 /* struct udf_mount *ump = udf_node->ump; */
1228 kauth_cred_t cred
= ap
->a_cred
;
1229 struct vattr
*vap
= ap
->a_vap
;
1232 DPRINTF(CALL
, ("udf_setattr called\n"));
1234 /* Abort if any unsettable attribute is given. */
1236 if (vap
->va_type
!= VNON
||
1237 vap
->va_nlink
!= VNOVAL
||
1238 vap
->va_fsid
!= VNOVAL
||
1239 vap
->va_fileid
!= VNOVAL
||
1240 vap
->va_blocksize
!= VNOVAL
||
1242 /* checks are debated */
1243 vap
->va_ctime
.tv_sec
!= VNOVAL
||
1244 vap
->va_ctime
.tv_nsec
!= VNOVAL
||
1245 vap
->va_birthtime
.tv_sec
!= VNOVAL
||
1246 vap
->va_birthtime
.tv_nsec
!= VNOVAL
||
1248 vap
->va_gen
!= VNOVAL
||
1249 vap
->va_rdev
!= VNOVAL
||
1250 vap
->va_bytes
!= VNOVAL
)
1253 DPRINTF(ATTR
, ("setattr changing:\n"));
1254 if (error
== 0 && (vap
->va_flags
!= VNOVAL
)) {
1255 DPRINTF(ATTR
, ("\tchflags\n"));
1256 error
= udf_chflags(vp
, vap
->va_flags
, cred
);
1259 if (error
== 0 && (vap
->va_size
!= VNOVAL
)) {
1260 DPRINTF(ATTR
, ("\tchsize\n"));
1261 error
= udf_chsize(vp
, vap
->va_size
, cred
);
1264 if (error
== 0 && (vap
->va_uid
!= VNOVAL
|| vap
->va_gid
!= VNOVAL
)) {
1265 DPRINTF(ATTR
, ("\tchown\n"));
1266 error
= udf_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
);
1269 if (error
== 0 && (vap
->va_mode
!= VNOVAL
)) {
1270 DPRINTF(ATTR
, ("\tchmod\n"));
1271 error
= udf_chmod(vp
, vap
->va_mode
, cred
);
1275 ((vap
->va_atime
.tv_sec
!= VNOVAL
&&
1276 vap
->va_atime
.tv_nsec
!= VNOVAL
) ||
1277 (vap
->va_mtime
.tv_sec
!= VNOVAL
&&
1278 vap
->va_mtime
.tv_nsec
!= VNOVAL
))
1280 DPRINTF(ATTR
, ("\tchtimes\n"));
1281 error
= udf_chtimes(vp
, &vap
->va_atime
, &vap
->va_mtime
,
1282 &vap
->va_birthtime
, vap
->va_vaflags
, cred
);
1284 VN_KNOTE(vp
, NOTE_ATTRIB
);
1289 /* --------------------------------------------------------------------- */
1292 * Return POSIX pathconf information for UDF file systems.
1295 udf_pathconf(void *v
)
1297 struct vop_pathconf_args
/* {
1300 register_t *a_retval;
1304 DPRINTF(CALL
, ("udf_pathconf called\n"));
1306 switch (ap
->a_name
) {
1308 *ap
->a_retval
= (1<<16)-1; /* 16 bits */
1311 *ap
->a_retval
= UDF_MAXNAMLEN
;
1314 *ap
->a_retval
= PATH_MAX
;
1317 *ap
->a_retval
= PIPE_BUF
;
1319 case _PC_CHOWN_RESTRICTED
:
1326 *ap
->a_retval
= 0; /* synchronised is off for performance */
1328 case _PC_FILESIZEBITS
:
1329 /* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */
1330 bits
= 64; /* XXX ought to deliver 65 */
1333 bits
= 64 * vp
->v_mount
->mnt_dev_bshift
;
1335 *ap
->a_retval
= bits
;
1343 /* --------------------------------------------------------------------- */
1348 struct vop_open_args
/* {
1351 kauth_cred_t a_cred;
1356 DPRINTF(CALL
, ("udf_open called\n"));
1359 * Files marked append-only must be opened for appending.
1360 * TODO: get chflags(2) flags from extened attribute.
1363 if ((flags
& APPEND
) && (ap
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)
1370 /* --------------------------------------------------------------------- */
1375 struct vop_close_args
/* {
1378 kauth_cred_t a_cred;
1381 struct vnode
*vp
= ap
->a_vp
;
1382 struct udf_node
*udf_node
= VTOI(vp
);
1383 int async
= vp
->v_mount
->mnt_flag
& MNT_ASYNC
;
1386 DPRINTF(CALL
, ("udf_close called\n"));
1387 udf_node
= udf_node
; /* shut up gcc */
1389 if (!async
&& (vp
->v_type
!= VDIR
)) {
1390 mutex_enter(vp
->v_interlock
);
1391 error
= VOP_PUTPAGES(vp
, 0, 0, PGO_CLEANIT
);
1396 mutex_enter(vp
->v_interlock
);
1397 if (vp
->v_usecount
> 1)
1398 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
1399 mutex_exit(vp
->v_interlock
);
1405 /* --------------------------------------------------------------------- */
1408 udf_check_possible(struct vnode
*vp
, struct vattr
*vap
, mode_t mode
)
1412 /* check if we are allowed to write */
1413 switch (vap
->va_type
) {
1418 * normal nodes: check if we're on a read-only mounted
1419 * filingsystem and bomb out if we're trying to write.
1421 if ((mode
& VWRITE
) && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
))
1429 * special nodes: even on read-only mounted filingsystems
1430 * these are allowed to be written to if permissions allow.
1434 /* no idea what this is */
1438 /* noone may write immutable files */
1439 /* TODO: get chflags(2) flags from extened attribute. */
1441 if ((mode
& VWRITE
) && (flags
& IMMUTABLE
))
1448 udf_check_permitted(struct vnode
*vp
, struct vattr
*vap
, mode_t mode
,
1451 /* ask the generic genfs_can_access to advice on security */
1452 return kauth_authorize_vnode(cred
, KAUTH_ACCESS_ACTION(mode
,
1453 vp
->v_type
, vap
->va_mode
), vp
, NULL
, genfs_can_access(vp
->v_type
,
1454 vap
->va_mode
, vap
->va_uid
, vap
->va_gid
, mode
, cred
));
1460 struct vop_access_args
/* {
1463 kauth_cred_t a_cred;
1466 struct vnode
*vp
= ap
->a_vp
;
1467 mode_t mode
= ap
->a_mode
;
1468 kauth_cred_t cred
= ap
->a_cred
;
1469 /* struct udf_node *udf_node = VTOI(vp); */
1473 DPRINTF(CALL
, ("udf_access called\n"));
1475 error
= VOP_GETATTR(vp
, &vap
, NULL
);
1479 error
= udf_check_possible(vp
, &vap
, mode
);
1483 error
= udf_check_permitted(vp
, &vap
, mode
, cred
);
1488 /* --------------------------------------------------------------------- */
1493 struct vop_create_v3_args
/* {
1494 struct vnode *a_dvp;
1495 struct vnode **a_vpp;
1496 struct componentname *a_cnp;
1497 struct vattr *a_vap;
1499 struct vnode
*dvp
= ap
->a_dvp
;
1500 struct vnode
**vpp
= ap
->a_vpp
;
1501 struct vattr
*vap
= ap
->a_vap
;
1502 struct componentname
*cnp
= ap
->a_cnp
;
1505 DPRINTF(CALL
, ("udf_create called\n"));
1506 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1511 /* --------------------------------------------------------------------- */
1516 struct vop_mknod_v3_args
/* {
1517 struct vnode *a_dvp;
1518 struct vnode **a_vpp;
1519 struct componentname *a_cnp;
1520 struct vattr *a_vap;
1522 struct vnode
*dvp
= ap
->a_dvp
;
1523 struct vnode
**vpp
= ap
->a_vpp
;
1524 struct vattr
*vap
= ap
->a_vap
;
1525 struct componentname
*cnp
= ap
->a_cnp
;
1528 DPRINTF(CALL
, ("udf_mknod called\n"));
1529 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1534 /* --------------------------------------------------------------------- */
1539 struct vop_mkdir_v3_args
/* {
1540 struct vnode *a_dvp;
1541 struct vnode **a_vpp;
1542 struct componentname *a_cnp;
1543 struct vattr *a_vap;
1545 struct vnode
*dvp
= ap
->a_dvp
;
1546 struct vnode
**vpp
= ap
->a_vpp
;
1547 struct vattr
*vap
= ap
->a_vap
;
1548 struct componentname
*cnp
= ap
->a_cnp
;
1551 DPRINTF(CALL
, ("udf_mkdir called\n"));
1552 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1557 /* --------------------------------------------------------------------- */
1560 udf_do_link(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
)
1562 struct udf_node
*udf_node
, *dir_node
;
1566 DPRINTF(CALL
, ("udf_link called\n"));
1568 KASSERT(vp
->v_type
!= VDIR
);
1569 KASSERT(dvp
->v_mount
== vp
->v_mount
);
1571 /* get attributes */
1572 dir_node
= VTOI(dvp
);
1573 udf_node
= VTOI(vp
);
1575 error
= VOP_GETATTR(vp
, &vap
, FSCRED
);
1581 /* check link count overflow */
1582 if (vap
.va_nlink
>= (1<<16)-1) { /* uint16_t */
1587 error
= udf_dir_attach(dir_node
->ump
, dir_node
, udf_node
, &vap
, cnp
);
1596 struct vop_link_v2_args
/* {
1597 struct vnode *a_dvp;
1599 struct componentname *a_cnp;
1601 struct vnode
*dvp
= ap
->a_dvp
;
1602 struct vnode
*vp
= ap
->a_vp
;
1603 struct componentname
*cnp
= ap
->a_cnp
;
1606 error
= udf_do_link(dvp
, vp
, cnp
);
1608 VOP_ABORTOP(dvp
, cnp
);
1610 VN_KNOTE(vp
, NOTE_LINK
);
1611 VN_KNOTE(dvp
, NOTE_WRITE
);
1616 /* --------------------------------------------------------------------- */
1619 udf_do_symlink(struct udf_node
*udf_node
, char *target
)
1621 struct pathcomp pathcomp
;
1622 uint8_t *pathbuf
, *pathpos
, *compnamepos
;
1624 int pathlen
, len
, compnamelen
, mntonnamelen
;
1627 /* process `target' to an UDF structure */
1628 pathbuf
= malloc(UDF_SYMLINKBUFLEN
, M_UDFTEMP
, M_WAITOK
);
1632 if (*target
== '/') {
1633 /* symlink starts from the root */
1634 len
= UDF_PATH_COMP_SIZE
;
1635 memset(&pathcomp
, 0, len
);
1636 pathcomp
.type
= UDF_PATH_COMP_ROOT
;
1638 /* check if its mount-point relative! */
1639 mntonname
= udf_node
->ump
->vfs_mountp
->mnt_stat
.f_mntonname
;
1640 mntonnamelen
= strlen(mntonname
);
1641 if (strlen(target
) >= mntonnamelen
) {
1642 if (strncmp(target
, mntonname
, mntonnamelen
) == 0) {
1643 pathcomp
.type
= UDF_PATH_COMP_MOUNTROOT
;
1644 target
+= mntonnamelen
;
1650 memcpy(pathpos
, &pathcomp
, len
);
1657 /* ignore multiple '/' */
1658 while (*target
== '/') {
1664 /* extract component name */
1666 compnamepos
= target
;
1667 while ((*target
) && (*target
!= '/')) {
1672 /* just trunc if too long ?? (security issue) */
1673 if (compnamelen
>= 127) {
1674 error
= ENAMETOOLONG
;
1678 /* convert unix name to UDF name */
1679 len
= sizeof(struct pathcomp
);
1680 memset(&pathcomp
, 0, len
);
1681 pathcomp
.type
= UDF_PATH_COMP_NAME
;
1682 len
= UDF_PATH_COMP_SIZE
;
1684 if ((compnamelen
== 2) && (strncmp(compnamepos
, "..", 2) == 0))
1685 pathcomp
.type
= UDF_PATH_COMP_PARENTDIR
;
1686 if ((compnamelen
== 1) && (*compnamepos
== '.'))
1687 pathcomp
.type
= UDF_PATH_COMP_CURDIR
;
1689 if (pathcomp
.type
== UDF_PATH_COMP_NAME
) {
1691 (char *) &pathcomp
.ident
, &pathcomp
.l_ci
,
1692 compnamepos
, compnamelen
,
1693 &udf_node
->ump
->logical_vol
->desc_charset
);
1694 len
= UDF_PATH_COMP_SIZE
+ pathcomp
.l_ci
;
1697 if (pathlen
+ len
>= UDF_SYMLINKBUFLEN
) {
1698 error
= ENAMETOOLONG
;
1702 memcpy(pathpos
, &pathcomp
, len
);
1708 /* aparently too big */
1709 free(pathbuf
, M_UDFTEMP
);
1713 error
= udf_grow_node(udf_node
, pathlen
);
1715 /* failed to pregrow node */
1716 free(pathbuf
, M_UDFTEMP
);
1720 /* write out structure on the new file */
1721 error
= vn_rdwr(UIO_WRITE
, udf_node
->vnode
,
1722 pathbuf
, pathlen
, 0,
1723 UIO_SYSSPACE
, IO_NODELOCKED
| IO_ALTSEMANTICS
,
1724 FSCRED
, NULL
, NULL
);
1726 /* return status of symlink contents writeout */
1727 free(pathbuf
, M_UDFTEMP
);
1733 udf_symlink(void *v
)
1735 struct vop_symlink_v3_args
/* {
1736 struct vnode *a_dvp;
1737 struct vnode **a_vpp;
1738 struct componentname *a_cnp;
1739 struct vattr *a_vap;
1742 struct vnode
*dvp
= ap
->a_dvp
;
1743 struct vnode
**vpp
= ap
->a_vpp
;
1744 struct vattr
*vap
= ap
->a_vap
;
1745 struct componentname
*cnp
= ap
->a_cnp
;
1746 struct udf_node
*dir_node
;
1747 struct udf_node
*udf_node
;
1750 DPRINTF(CALL
, ("udf_symlink called\n"));
1751 DPRINTF(CALL
, ("\tlinking to `%s`\n", ap
->a_target
));
1752 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1753 KASSERT(((error
== 0) && (*vpp
!= NULL
)) || ((error
&& (*vpp
== NULL
))));
1755 dir_node
= VTOI(dvp
);
1756 udf_node
= VTOI(*vpp
);
1758 error
= udf_do_symlink(udf_node
, ap
->a_target
);
1761 udf_dir_detach(udf_node
->ump
, dir_node
, udf_node
, cnp
);
1769 /* --------------------------------------------------------------------- */
1772 udf_do_readlink(struct udf_node
*udf_node
, uint64_t filesize
,
1773 uint8_t *targetbuf
, int *length
)
1775 struct pathcomp pathcomp
;
1776 uint8_t *pathbuf
, *tmpname
;
1777 uint8_t *pathpos
, *targetpos
;
1779 int pathlen
, targetlen
, namelen
, mntonnamelen
, len
, l_ci
;
1782 pathbuf
= malloc(UDF_SYMLINKBUFLEN
, M_UDFTEMP
, M_WAITOK
);
1783 tmpname
= malloc(PATH_MAX
+1, M_UDFTEMP
, M_WAITOK
);
1784 memset(pathbuf
, 0, UDF_SYMLINKBUFLEN
);
1785 memset(targetbuf
, 0, PATH_MAX
);
1787 /* read contents of file in our temporary buffer */
1788 error
= vn_rdwr(UIO_READ
, udf_node
->vnode
,
1789 pathbuf
, filesize
, 0,
1790 UIO_SYSSPACE
, IO_NODELOCKED
| IO_ALTSEMANTICS
,
1791 FSCRED
, NULL
, NULL
);
1793 /* failed to read in symlink contents */
1794 free(pathbuf
, M_UDFTEMP
);
1795 free(tmpname
, M_UDFTEMP
);
1799 /* convert to a unix path */
1802 targetpos
= targetbuf
;
1803 targetlen
= PATH_MAX
;
1804 mntonname
= udf_node
->ump
->vfs_mountp
->mnt_stat
.f_mntonname
;
1805 mntonnamelen
= strlen(mntonname
);
1809 while (filesize
- pathlen
>= UDF_PATH_COMP_SIZE
) {
1810 len
= UDF_PATH_COMP_SIZE
;
1811 memcpy(&pathcomp
, pathpos
, len
);
1812 l_ci
= pathcomp
.l_ci
;
1813 switch (pathcomp
.type
) {
1814 case UDF_PATH_COMP_ROOT
:
1815 /* XXX should check for l_ci; bugcompatible now */
1816 if ((targetlen
< 1) || !first
) {
1820 *targetpos
++ = '/'; targetlen
--;
1822 case UDF_PATH_COMP_MOUNTROOT
:
1823 /* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */
1824 if (l_ci
|| (targetlen
< mntonnamelen
+1) || !first
) {
1828 memcpy(targetpos
, mntonname
, mntonnamelen
);
1829 targetpos
+= mntonnamelen
; targetlen
-= mntonnamelen
;
1830 if (filesize
-pathlen
> UDF_PATH_COMP_SIZE
+l_ci
) {
1831 /* more follows, so must be directory */
1832 *targetpos
++ = '/'; targetlen
--;
1835 case UDF_PATH_COMP_PARENTDIR
:
1836 /* XXX should check for l_ci; bugcompatible now */
1837 if (targetlen
< 3) {
1841 *targetpos
++ = '.'; targetlen
--;
1842 *targetpos
++ = '.'; targetlen
--;
1843 *targetpos
++ = '/'; targetlen
--;
1845 case UDF_PATH_COMP_CURDIR
:
1846 /* XXX should check for l_ci; bugcompatible now */
1847 if (targetlen
< 2) {
1851 *targetpos
++ = '.'; targetlen
--;
1852 *targetpos
++ = '/'; targetlen
--;
1854 case UDF_PATH_COMP_NAME
:
1859 memset(tmpname
, 0, PATH_MAX
);
1860 memcpy(&pathcomp
, pathpos
, len
+ l_ci
);
1861 udf_to_unix_name(tmpname
, MAXPATHLEN
,
1862 pathcomp
.ident
, l_ci
,
1863 &udf_node
->ump
->logical_vol
->desc_charset
);
1864 namelen
= strlen(tmpname
);
1865 if (targetlen
< namelen
+ 1) {
1869 memcpy(targetpos
, tmpname
, namelen
);
1870 targetpos
+= namelen
; targetlen
-= namelen
;
1871 if (filesize
-pathlen
> UDF_PATH_COMP_SIZE
+l_ci
) {
1872 /* more follows, so must be directory */
1873 *targetpos
++ = '/'; targetlen
--;
1883 pathpos
+= UDF_PATH_COMP_SIZE
+ l_ci
;
1884 pathlen
+= UDF_PATH_COMP_SIZE
+ l_ci
;
1887 /* all processed? */
1888 if (filesize
- pathlen
> 0)
1891 free(pathbuf
, M_UDFTEMP
);
1892 free(tmpname
, M_UDFTEMP
);
1894 *length
= PATH_MAX
- targetlen
;
1900 udf_readlink(void *v
)
1902 struct vop_readlink_args
/* {
1905 kauth_cred_t a_cred;
1907 struct vnode
*vp
= ap
->a_vp
;
1908 struct udf_node
*udf_node
= VTOI(vp
);
1909 struct file_entry
*fe
= udf_node
->fe
;
1910 struct extfile_entry
*efe
= udf_node
->efe
;
1911 struct uio
*uio
= ap
->a_uio
;
1917 DPRINTF(CALL
, ("udf_readlink called\n"));
1920 filesize
= udf_rw64(fe
->inf_len
);
1922 assert(udf_node
->efe
);
1923 filesize
= udf_rw64(efe
->inf_len
);
1926 /* claim temporary buffers for translation */
1927 targetbuf
= malloc(PATH_MAX
+1, M_UDFTEMP
, M_WAITOK
);
1929 error
= udf_do_readlink(udf_node
, filesize
, targetbuf
, &length
);
1931 /* uiomove() to destination */
1933 uiomove(targetbuf
, length
, uio
);
1935 free(targetbuf
, M_UDFTEMP
);
1939 /* --------------------------------------------------------------------- */
1942 * udf_rename() moved to udf_rename.c
1945 /* --------------------------------------------------------------------- */
1950 struct vop_remove_args
/* {
1951 struct vnode *a_dvp;
1953 struct componentname *a_cnp;
1955 struct vnode
*dvp
= ap
->a_dvp
;
1956 struct vnode
*vp
= ap
->a_vp
;
1957 struct componentname
*cnp
= ap
->a_cnp
;
1958 struct udf_node
*dir_node
= VTOI(dvp
);
1959 struct udf_node
*udf_node
= VTOI(vp
);
1960 struct udf_mount
*ump
= dir_node
->ump
;
1963 DPRINTF(CALL
, ("udf_remove called\n"));
1964 if (vp
->v_type
!= VDIR
) {
1965 error
= udf_dir_detach(ump
, dir_node
, udf_node
, cnp
);
1966 DPRINTFIF(NODE
, error
, ("\tgot error removing file\n"));
1968 DPRINTF(NODE
, ("\tis a directory: perm. denied\n"));
1973 VN_KNOTE(vp
, NOTE_DELETE
);
1974 VN_KNOTE(dvp
, NOTE_WRITE
);
1986 /* --------------------------------------------------------------------- */
1991 struct vop_rmdir_args
/* {
1992 struct vnode *a_dvp;
1994 struct componentname *a_cnp;
1996 struct vnode
*vp
= ap
->a_vp
;
1997 struct vnode
*dvp
= ap
->a_dvp
;
1998 struct componentname
*cnp
= ap
->a_cnp
;
1999 struct udf_node
*dir_node
= VTOI(dvp
);
2000 struct udf_node
*udf_node
= VTOI(vp
);
2001 struct udf_mount
*ump
= dir_node
->ump
;
2004 DPRINTF(NOTIMPL
, ("udf_rmdir '%s' called\n", cnp
->cn_nameptr
));
2006 /* don't allow '.' to be deleted */
2007 if (dir_node
== udf_node
) {
2013 /* make sure our `leaf' node's hash is populated */
2014 dirhash_get(&udf_node
->dir_hash
);
2015 error
= udf_dirhash_fill(udf_node
);
2017 dirhash_put(udf_node
->dir_hash
);
2021 /* check to see if the directory is empty */
2022 isempty
= dirhash_dir_isempty(udf_node
->dir_hash
);
2023 dirhash_put(udf_node
->dir_hash
);
2031 /* detach the node from the directory, udf_node is an empty dir here */
2032 error
= udf_dir_detach(ump
, dir_node
, udf_node
, cnp
);
2035 // cache_purge(dvp); /* XXX from msdosfs, why? */
2037 * Bug alert: we need to remove '..' from the detaching
2038 * udf_node so further lookups of this are not possible. This
2039 * prevents a process in a deleted directory from going to its
2040 * deleted parent. Since `udf_node' is garanteed to be empty
2041 * here, trunc it so no fids are there.
2043 dirhash_purge(&udf_node
->dir_hash
);
2044 udf_shrink_node(udf_node
, 0);
2045 VN_KNOTE(vp
, NOTE_DELETE
);
2047 DPRINTFIF(NODE
, error
, ("\tgot error removing dir\n"));
2049 /* unput the nodes and exit */
2056 /* --------------------------------------------------------------------- */
2061 struct vop_fsync_args
/* {
2063 kauth_cred_t a_cred;
2069 struct vnode
*vp
= ap
->a_vp
;
2070 struct udf_node
*udf_node
= VTOI(vp
);
2071 int error
, flags
, wait
;
2073 DPRINTF(SYNC
, ("udf_fsync called on %p : %s, %s\n",
2075 (ap
->a_flags
& FSYNC_WAIT
) ? "wait":"no wait",
2076 (ap
->a_flags
& FSYNC_DATAONLY
) ? "data_only":"complete"));
2078 /* flush data and wait for it when requested */
2079 wait
= (ap
->a_flags
& FSYNC_WAIT
) ? UPDATE_WAIT
: 0;
2080 error
= vflushbuf(vp
, ap
->a_flags
);
2084 if (udf_node
== NULL
) {
2085 printf("udf_fsync() called on NULL udf_node!\n");
2088 if (vp
->v_tag
!= VT_UDF
) {
2089 printf("udf_fsync() called on node not tagged as UDF node!\n");
2094 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
2096 /* if called when mounted readonly, never write back */
2097 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
2100 /* if only data is requested, return */
2101 if (ap
->a_flags
& FSYNC_DATAONLY
)
2104 /* check if the node is dirty 'enough'*/
2105 flags
= udf_node
->i_flags
& (IN_MODIFIED
| IN_ACCESSED
);
2109 /* if we don't have to wait, check for IO pending */
2111 if (vp
->v_numoutput
> 0) {
2112 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on v_numoutput\n", udf_node
));
2115 if (udf_node
->outstanding_bufs
> 0) {
2116 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on outstanding_bufs\n", udf_node
));
2119 if (udf_node
->outstanding_nodedscr
> 0) {
2120 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on outstanding_nodedscr\n", udf_node
));
2125 /* wait until vp->v_numoutput reaches zero i.e. is finished */
2127 DPRINTF(SYNC
, ("udf_fsync %p, waiting\n", udf_node
));
2128 mutex_enter(vp
->v_interlock
);
2129 while (vp
->v_numoutput
) {
2130 DPRINTF(SYNC
, ("udf_fsync %p, v_numoutput %d\n", udf_node
, vp
->v_numoutput
));
2131 cv_timedwait(&vp
->v_cv
, vp
->v_interlock
, hz
/8);
2133 mutex_exit(vp
->v_interlock
);
2134 DPRINTF(SYNC
, ("udf_fsync %p, fin wait\n", udf_node
));
2137 /* write out node and wait for it if requested */
2138 DPRINTF(SYNC
, ("udf_fsync %p, writeout node\n", udf_node
));
2139 error
= udf_writeout_node(udf_node
, wait
);
2143 /* TODO/XXX if ap->a_flags & FSYNC_CACHE, we ought to do a disc sync */
2148 /* --------------------------------------------------------------------- */
2151 udf_advlock(void *v
)
2153 struct vop_advlock_args
/* {
2160 struct vnode
*vp
= ap
->a_vp
;
2161 struct udf_node
*udf_node
= VTOI(vp
);
2162 struct file_entry
*fe
;
2163 struct extfile_entry
*efe
;
2166 DPRINTF(LOCKING
, ("udf_advlock called\n"));
2168 /* get directory filesize */
2171 file_size
= udf_rw64(fe
->inf_len
);
2173 assert(udf_node
->efe
);
2174 efe
= udf_node
->efe
;
2175 file_size
= udf_rw64(efe
->inf_len
);
2178 return lf_advlock(ap
, &udf_node
->lockf
, file_size
);
2181 /* --------------------------------------------------------------------- */
2183 /* Global vfs vnode data structures for udfs */
2184 int (**udf_vnodeop_p
)(void *);
2186 const struct vnodeopv_entry_desc udf_vnodeop_entries
[] = {
2187 { &vop_default_desc
, vn_default_error
},
2188 { &vop_lookup_desc
, udf_lookup
}, /* lookup */
2189 { &vop_create_desc
, udf_create
}, /* create */
2190 { &vop_mknod_desc
, udf_mknod
}, /* mknod */ /* TODO */
2191 { &vop_open_desc
, udf_open
}, /* open */
2192 { &vop_close_desc
, udf_close
}, /* close */
2193 { &vop_access_desc
, udf_access
}, /* access */
2194 { &vop_getattr_desc
, udf_getattr
}, /* getattr */
2195 { &vop_setattr_desc
, udf_setattr
}, /* setattr */ /* TODO chflags */
2196 { &vop_read_desc
, udf_read
}, /* read */
2197 { &vop_write_desc
, udf_write
}, /* write */ /* WRITE */
2198 { &vop_fallocate_desc
, genfs_eopnotsupp
}, /* fallocate */
2199 { &vop_fdiscard_desc
, genfs_eopnotsupp
}, /* fdiscard */
2200 { &vop_fcntl_desc
, genfs_fcntl
}, /* fcntl */ /* TODO? */
2201 { &vop_ioctl_desc
, genfs_enoioctl
}, /* ioctl */ /* TODO? */
2202 { &vop_poll_desc
, genfs_poll
}, /* poll */ /* TODO/OK? */
2203 { &vop_kqfilter_desc
, genfs_kqfilter
}, /* kqfilter */ /* ? */
2204 { &vop_revoke_desc
, genfs_revoke
}, /* revoke */ /* TODO? */
2205 { &vop_mmap_desc
, genfs_mmap
}, /* mmap */ /* OK? */
2206 { &vop_fsync_desc
, udf_fsync
}, /* fsync */
2207 { &vop_seek_desc
, genfs_seek
}, /* seek */
2208 { &vop_remove_desc
, udf_remove
}, /* remove */
2209 { &vop_link_desc
, udf_link
}, /* link */ /* TODO */
2210 { &vop_rename_desc
, udf_rename
}, /* rename */ /* TODO */
2211 { &vop_mkdir_desc
, udf_mkdir
}, /* mkdir */
2212 { &vop_rmdir_desc
, udf_rmdir
}, /* rmdir */
2213 { &vop_symlink_desc
, udf_symlink
}, /* symlink */ /* TODO */
2214 { &vop_readdir_desc
, udf_readdir
}, /* readdir */
2215 { &vop_readlink_desc
, udf_readlink
}, /* readlink */ /* TEST ME */
2216 { &vop_abortop_desc
, genfs_abortop
}, /* abortop */ /* TODO/OK? */
2217 { &vop_inactive_desc
, udf_inactive
}, /* inactive */
2218 { &vop_reclaim_desc
, udf_reclaim
}, /* reclaim */
2219 { &vop_lock_desc
, genfs_lock
}, /* lock */
2220 { &vop_unlock_desc
, genfs_unlock
}, /* unlock */
2221 { &vop_bmap_desc
, udf_trivial_bmap
}, /* bmap */ /* 1:1 bmap */
2222 { &vop_strategy_desc
, udf_vfsstrategy
},/* strategy */
2223 /* { &vop_print_desc, udf_print }, */ /* print */
2224 { &vop_islocked_desc
, genfs_islocked
}, /* islocked */
2225 { &vop_pathconf_desc
, udf_pathconf
}, /* pathconf */
2226 { &vop_advlock_desc
, udf_advlock
}, /* advlock */ /* TEST ME */
2227 { &vop_bwrite_desc
, vn_bwrite
}, /* bwrite */ /* ->strategy */
2228 { &vop_getpages_desc
, genfs_getpages
}, /* getpages */
2229 { &vop_putpages_desc
, genfs_putpages
}, /* putpages */
2234 const struct vnodeopv_desc udf_vnodeop_opv_desc
= {
2235 &udf_vnodeop_p
, udf_vnodeop_entries