1 /* $NetBSD: udf_vnops.c,v 1.56 2010/01/05 13:30:11 mbalmer 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.56 2010/01/05 13:30:11 mbalmer 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>
63 #include "udf_bswap.h"
66 #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
72 /* implementations of vnode functions; table follows at end */
73 /* --------------------------------------------------------------------- */
78 struct vop_inactive_args
/* {
82 struct vnode
*vp
= ap
->a_vp
;
83 struct udf_node
*udf_node
= VTOI(vp
);
86 DPRINTF(NODE
, ("udf_inactive called for udf_node %p\n", VTOI(vp
)));
88 if (udf_node
== NULL
) {
89 DPRINTF(NODE
, ("udf_inactive: inactive NULL UDF node\n"));
95 * Optionally flush metadata to disc. If the file has not been
96 * referenced anymore in a directory we ought to free up the resources
97 * on disc if applicable.
100 refcnt
= udf_rw16(udf_node
->fe
->link_cnt
);
102 assert(udf_node
->efe
);
103 refcnt
= udf_rw16(udf_node
->efe
->link_cnt
);
106 if ((refcnt
== 0) && (vp
->v_vflag
& VV_SYSTEM
)) {
107 DPRINTF(VOLUMES
, ("UDF_INACTIVE deleting VV_SYSTEM\n"));
108 /* system nodes are not writen out on inactive, so flush */
109 udf_node
->i_flags
= 0;
112 *ap
->a_recycle
= false;
113 if ((refcnt
== 0) && ((vp
->v_vflag
& VV_SYSTEM
) == 0)) {
114 /* remove this file's allocation */
115 DPRINTF(NODE
, ("udf_inactive deleting unlinked file\n"));
116 *ap
->a_recycle
= true;
117 udf_delete_node(udf_node
);
119 vrecycle(vp
, NULL
, curlwp
);
123 /* write out its node */
124 if (udf_node
->i_flags
& (IN_CHANGE
| IN_UPDATE
| IN_MODIFIED
))
125 udf_update(vp
, NULL
, NULL
, NULL
, 0);
131 /* --------------------------------------------------------------------- */
133 int udf_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
, struct lwp
*lwp
);
138 struct vop_reclaim_args
/* {
141 struct vnode
*vp
= ap
->a_vp
;
142 struct udf_node
*udf_node
= VTOI(vp
);
144 DPRINTF(NODE
, ("udf_reclaim called for node %p\n", udf_node
));
145 if (prtactive
&& vp
->v_usecount
> 1)
146 vprint("udf_reclaim(): pushing active", vp
);
148 if (udf_node
== NULL
) {
149 DPRINTF(NODE
, ("udf_reclaim(): null udfnode\n"));
153 /* update note for closure */
154 udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_CLOSE
);
156 /* async check to see if all node descriptors are written out */
157 while ((volatile int) udf_node
->outstanding_nodedscr
> 0) {
158 vprint("udf_reclaim(): waiting for writeout\n", vp
);
159 tsleep(&udf_node
->outstanding_nodedscr
, PRIBIO
, "recl wait", hz
/8);
162 /* purge old data from namei */
165 /* dispose all node knowledge */
166 udf_dispose_node(udf_node
);
171 /* --------------------------------------------------------------------- */
176 struct vop_read_args
/* {
182 struct vnode
*vp
= ap
->a_vp
;
183 struct uio
*uio
= ap
->a_uio
;
184 int ioflag
= ap
->a_ioflag
;
185 int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
186 struct uvm_object
*uobj
;
187 struct udf_node
*udf_node
= VTOI(vp
);
188 struct file_entry
*fe
;
189 struct extfile_entry
*efe
;
195 * XXX reading from extended attributes not yet implemented. FreeBSD
196 * has it in mind to forward the IO_EXT read call to the
200 DPRINTF(READ
, ("udf_read called\n"));
202 /* can this happen? some filingsystems have this check */
203 if (uio
->uio_offset
< 0)
205 if (uio
->uio_resid
== 0)
208 /* protect against rogue programs reading raw directories and links */
209 if ((ioflag
& IO_ALTSEMANTICS
) == 0) {
210 if (vp
->v_type
== VDIR
)
212 /* all but regular files just give EINVAL */
213 if (vp
->v_type
!= VREG
)
218 assert(udf_node
->fe
|| udf_node
->efe
);
220 /* get file/directory filesize */
223 file_size
= udf_rw64(fe
->inf_len
);
225 assert(udf_node
->efe
);
227 file_size
= udf_rw64(efe
->inf_len
);
230 /* read contents using buffercache */
233 while (uio
->uio_resid
> 0) {
235 if (file_size
<= uio
->uio_offset
)
238 /* maximise length to file extremity */
239 len
= MIN(file_size
- uio
->uio_offset
, uio
->uio_resid
);
243 /* ubc, here we come, prepare to trap */
244 error
= ubc_uiomove(uobj
, uio
, len
, advice
,
245 UBC_READ
| UBC_PARTIALOK
| UBC_UNMAP_FLAG(vp
));
250 /* note access time unless not requested */
251 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
)) {
252 udf_node
->i_flags
|= IN_ACCESS
;
253 if ((ioflag
& IO_SYNC
) == IO_SYNC
)
254 error
= udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_WAIT
);
260 /* --------------------------------------------------------------------- */
265 struct vop_write_args
/* {
271 struct vnode
*vp
= ap
->a_vp
;
272 struct uio
*uio
= ap
->a_uio
;
273 int ioflag
= ap
->a_ioflag
;
274 kauth_cred_t cred
= ap
->a_cred
;
275 int advice
= IO_ADV_DECODE(ap
->a_ioflag
);
276 struct uvm_object
*uobj
;
277 struct udf_node
*udf_node
= VTOI(vp
);
278 struct file_entry
*fe
;
279 struct extfile_entry
*efe
;
280 uint64_t file_size
, old_size
, old_offset
;
282 int async
= vp
->v_mount
->mnt_flag
& MNT_ASYNC
;
283 int aflag
= ioflag
& IO_SYNC
? B_SYNC
: 0;
288 * XXX writing to extended attributes not yet implemented. FreeBSD has
289 * it in mind to forward the IO_EXT read call to the
293 DPRINTF(WRITE
, ("udf_write called\n"));
295 /* can this happen? some filingsystems have this check */
296 if (uio
->uio_offset
< 0)
298 if (uio
->uio_resid
== 0)
301 /* protect against rogue programs writing raw directories or links */
302 if ((ioflag
& IO_ALTSEMANTICS
) == 0) {
303 if (vp
->v_type
== VDIR
)
305 /* all but regular files just give EINVAL for now */
306 if (vp
->v_type
!= VREG
)
311 assert(udf_node
->fe
|| udf_node
->efe
);
313 /* get file/directory filesize */
316 file_size
= udf_rw64(fe
->inf_len
);
318 assert(udf_node
->efe
);
320 file_size
= udf_rw64(efe
->inf_len
);
322 old_size
= file_size
;
324 /* if explicitly asked to append, uio_offset can be wrong? */
325 if (ioflag
& IO_APPEND
)
326 uio
->uio_offset
= file_size
;
328 extended
= (uio
->uio_offset
+ uio
->uio_resid
> file_size
);
330 DPRINTF(WRITE
, ("extending file from %"PRIu64
" to %"PRIu64
"\n",
331 file_size
, uio
->uio_offset
+ uio
->uio_resid
));
332 error
= udf_grow_node(udf_node
, uio
->uio_offset
+ uio
->uio_resid
);
335 file_size
= uio
->uio_offset
+ uio
->uio_resid
;
338 /* write contents using buffercache */
340 resid
= uio
->uio_resid
;
343 uvm_vnp_setwritesize(vp
, file_size
);
344 old_offset
= uio
->uio_offset
;
345 while (uio
->uio_resid
> 0) {
346 /* maximise length to file extremity */
347 len
= MIN(file_size
- uio
->uio_offset
, uio
->uio_resid
);
351 genfs_node_wrlock(vp
);
352 error
= GOP_ALLOC(vp
, uio
->uio_offset
, len
, aflag
, cred
);
353 genfs_node_unlock(vp
);
357 /* ubc, here we come, prepare to trap */
358 error
= ubc_uiomove(uobj
, uio
, len
, advice
,
359 UBC_WRITE
| UBC_UNMAP_FLAG(vp
));
364 * flush what we just wrote if necessary.
365 * XXXUBC simplistic async flushing.
367 * Directories are excluded since its file data that we want
370 if (!async
&& (vp
->v_type
!= VDIR
) &&
371 (old_offset
>> 16 != uio
->uio_offset
>> 16)) {
372 mutex_enter(&vp
->v_interlock
);
373 error
= VOP_PUTPAGES(vp
, (old_offset
>> 16) << 16,
374 (uio
->uio_offset
>> 16) << 16, PGO_CLEANIT
);
375 old_offset
= uio
->uio_offset
;
378 uvm_vnp_setsize(vp
, file_size
);
380 /* mark node changed and request update */
381 udf_node
->i_flags
|= IN_CHANGE
| IN_UPDATE
;
384 * XXX TODO FFS has code here to reset setuid & setgid when we're not
385 * the superuser as a precaution against tampering.
388 /* if we wrote a thing, note write action on vnode */
389 if (resid
> uio
->uio_resid
)
390 VN_KNOTE(vp
, NOTE_WRITE
| (extended
? NOTE_EXTEND
: 0));
393 /* bring back file size to its former size */
394 /* take notice of its errors? */
395 (void) udf_chsize(vp
, (u_quad_t
) old_size
, cred
);
398 uio
->uio_offset
-= resid
- uio
->uio_resid
;
399 uio
->uio_resid
= resid
;
401 /* if we write and we're synchronous, update node */
402 if ((resid
> uio
->uio_resid
) && ((ioflag
& IO_SYNC
) == IO_SYNC
))
403 error
= udf_update(vp
, NULL
, NULL
, NULL
, UPDATE_WAIT
);
410 /* --------------------------------------------------------------------- */
413 * `Special' bmap functionality that translates all incomming requests to
414 * translate to vop_strategy() calls with the same blocknumbers effectively
415 * not translating at all.
419 udf_trivial_bmap(void *v
)
421 struct vop_bmap_args
/* {
424 struct vnode **a_vpp;
428 struct vnode
*vp
= ap
->a_vp
; /* our node */
429 struct vnode
**vpp
= ap
->a_vpp
; /* return node */
430 daddr_t
*bnp
= ap
->a_bnp
; /* translated */
431 daddr_t bn
= ap
->a_bn
; /* origional */
432 int *runp
= ap
->a_runp
;
433 struct udf_node
*udf_node
= VTOI(vp
);
436 /* get logical block size */
437 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
439 /* could return `-1' to indicate holes/zeros */
443 /* set the vnode to read the data from with strategy on itself */
447 /* set runlength of maximum block size */
449 *runp
= MAXPHYS
/ lb_size
; /* or with -1 ? */
455 /* --------------------------------------------------------------------- */
458 udf_vfsstrategy(void *v
)
460 struct vop_strategy_args
/* {
464 struct vnode
*vp
= ap
->a_vp
;
465 struct buf
*bp
= ap
->a_bp
;
466 struct udf_node
*udf_node
= VTOI(vp
);
467 uint32_t lb_size
, from
, sectors
;
470 DPRINTF(STRATEGY
, ("udf_strategy called\n"));
472 /* check if we ought to be here */
473 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
474 panic("udf_strategy: spec");
476 /* only filebuffers ought to be read/write by this, no descriptors */
477 assert(bp
->b_blkno
>= 0);
479 /* get sector size */
480 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
482 /* calculate sector to start from */
485 /* calculate length to fetch/store in sectors */
486 sectors
= bp
->b_bcount
/ lb_size
;
487 assert(bp
->b_bcount
> 0);
489 /* NEVER assume later that this buffer is already translated */
490 /* bp->b_lblkno = bp->b_blkno; */
492 /* check assertions: we OUGHT to always get multiples of this */
493 assert(sectors
* lb_size
== bp
->b_bcount
);
497 if (bp
->b_flags
& B_READ
) {
498 DPRINTF(STRATEGY
, ("\tread vp %p buf %p (blk no %"PRIu64
")"
499 ", sector %d for %d sectors\n",
500 vp
, bp
, bp
->b_blkno
, from
, sectors
));
502 /* read buffer from the udf_node, translate vtop on the way*/
503 udf_read_filebuf(udf_node
, bp
);
505 DPRINTF(STRATEGY
, ("\twrite vp %p buf %p (blk no %"PRIu64
")"
506 ", sector %d for %d sectors\n",
507 vp
, bp
, bp
->b_blkno
, from
, sectors
));
509 /* write buffer to the udf_node, translate vtop on the way*/
510 udf_write_filebuf(udf_node
, bp
);
516 /* --------------------------------------------------------------------- */
521 struct vop_readdir_args
/* {
529 struct uio
*uio
= ap
->a_uio
;
530 struct vnode
*vp
= ap
->a_vp
;
531 struct udf_node
*udf_node
= VTOI(vp
);
532 struct file_entry
*fe
;
533 struct extfile_entry
*efe
;
534 struct fileid_desc
*fid
;
535 struct dirent
*dirent
;
536 uint64_t file_size
, diroffset
, transoffset
;
540 DPRINTF(READDIR
, ("udf_readdir called\n"));
542 /* This operation only makes sense on directory nodes. */
543 if (vp
->v_type
!= VDIR
)
546 /* get directory filesize */
549 file_size
= udf_rw64(fe
->inf_len
);
551 assert(udf_node
->efe
);
553 file_size
= udf_rw64(efe
->inf_len
);
556 dirent
= malloc(sizeof(struct dirent
), M_UDFTEMP
, M_WAITOK
| M_ZERO
);
559 * Add `.' pseudo entry if at offset zero since its not in the fid
562 if (uio
->uio_offset
== 0) {
563 DPRINTF(READDIR
, ("\t'.' inserted\n"));
564 strcpy(dirent
->d_name
, ".");
565 dirent
->d_fileno
= udf_get_node_id(&udf_node
->loc
);
566 dirent
->d_type
= DT_DIR
;
567 dirent
->d_namlen
= strlen(dirent
->d_name
);
568 dirent
->d_reclen
= _DIRENT_SIZE(dirent
);
569 uiomove(dirent
, _DIRENT_SIZE(dirent
), uio
);
571 /* mark with magic value that we have done the dummy */
572 uio
->uio_offset
= UDF_DIRCOOKIE_DOT
;
575 /* we are called just as long as we keep on pushing data in */
577 if (uio
->uio_offset
< file_size
) {
578 /* allocate temporary space for fid */
579 lb_size
= udf_rw32(udf_node
->ump
->logical_vol
->lb_size
);
580 fid
= malloc(lb_size
, M_UDFTEMP
, M_WAITOK
);
582 if (uio
->uio_offset
== UDF_DIRCOOKIE_DOT
)
585 diroffset
= uio
->uio_offset
;
586 transoffset
= diroffset
;
587 while (diroffset
< file_size
) {
588 DPRINTF(READDIR
, ("\tread in fid stream\n"));
589 /* transfer a new fid/dirent */
590 error
= udf_read_fid_stream(vp
, &diroffset
, fid
, dirent
);
591 DPRINTFIF(READDIR
, error
, ("read error in read fid "
592 "stream : %d\n", error
));
597 * If there isn't enough space in the uio to return a
598 * whole dirent, break off read
600 if (uio
->uio_resid
< _DIRENT_SIZE(dirent
))
603 /* remember the last entry we transfered */
604 transoffset
= diroffset
;
606 /* skip deleted entries */
607 if (fid
->file_char
& UDF_FILE_CHAR_DEL
)
610 /* skip not visible files */
611 if (fid
->file_char
& UDF_FILE_CHAR_VIS
)
614 /* copy dirent to the caller */
615 DPRINTF(READDIR
, ("\tread dirent `%s', type %d\n",
616 dirent
->d_name
, dirent
->d_type
));
617 uiomove(dirent
, _DIRENT_SIZE(dirent
), uio
);
620 /* pass on last transfered offset */
621 uio
->uio_offset
= transoffset
;
622 free(fid
, M_UDFTEMP
);
626 *ap
->a_eofflag
= (uio
->uio_offset
>= file_size
);
629 if (udf_verbose
& UDF_DEBUG_READDIR
) {
630 printf("returning offset %d\n", (uint32_t) uio
->uio_offset
);
632 printf("returning EOF ? %d\n", *ap
->a_eofflag
);
634 printf("readdir returning error %d\n", error
);
638 free(dirent
, M_UDFTEMP
);
642 /* --------------------------------------------------------------------- */
647 struct vop_lookup_args
/* {
649 struct vnode **a_vpp;
650 struct componentname *a_cnp;
652 struct vnode
*dvp
= ap
->a_dvp
;
653 struct vnode
**vpp
= ap
->a_vpp
;
654 struct componentname
*cnp
= ap
->a_cnp
;
655 struct udf_node
*dir_node
, *res_node
;
656 struct udf_mount
*ump
;
657 struct long_ad icb_loc
;
659 int namelen
, nameiop
, islastcn
, mounted_ro
;
663 dir_node
= VTOI(dvp
);
667 DPRINTF(LOOKUP
, ("udf_lookup called\n"));
669 /* simplify/clarification flags */
670 nameiop
= cnp
->cn_nameiop
;
671 islastcn
= cnp
->cn_flags
& ISLASTCN
;
672 mounted_ro
= dvp
->v_mount
->mnt_flag
& MNT_RDONLY
;
674 /* check exec/dirread permissions first */
675 error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
);
679 DPRINTF(LOOKUP
, ("\taccess ok\n"));
682 * If requesting a modify on the last path element on a read-only
683 * filingsystem, reject lookup; XXX why is this repeated in every FS ?
685 if (islastcn
&& mounted_ro
&& (nameiop
== DELETE
|| nameiop
== RENAME
))
688 DPRINTF(LOOKUP
, ("\tlooking up cnp->cn_nameptr '%s'\n",
690 /* look in the nami cache; returns 0 on success!! */
691 error
= cache_lookup(dvp
, vpp
, cnp
);
695 DPRINTF(LOOKUP
, ("\tNOT found in cache\n"));
698 * Obviously, the file is not (anymore) in the namecache, we have to
699 * search for it. There are three basic cases: '.', '..' and others.
701 * Following the guidelines of VOP_LOOKUP manpage and tmpfs.
704 if ((cnp
->cn_namelen
== 1) && (cnp
->cn_nameptr
[0] == '.')) {
705 DPRINTF(LOOKUP
, ("\tlookup '.'\n"));
706 /* special case 1 '.' */
710 } else if (cnp
->cn_flags
& ISDOTDOT
) {
711 /* special case 2 '..' */
712 DPRINTF(LOOKUP
, ("\tlookup '..'\n"));
717 error
= udf_lookup_name_in_dir(dvp
, name
, namelen
,
724 /* first unlock parent */
728 DPRINTF(LOOKUP
, ("\tfound '..'\n"));
729 /* try to create/reuse the node */
730 error
= udf_get_node(ump
, &icb_loc
, &res_node
);
734 ("\tnode retrieved/created OK\n"));
735 *vpp
= res_node
->vnode
;
739 /* try to relock parent */
740 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
742 DPRINTF(LOOKUP
, ("\tlookup file\n"));
743 /* all other files */
744 /* lookup filename in the directory; location icb_loc */
745 name
= cnp
->cn_nameptr
;
746 namelen
= cnp
->cn_namelen
;
747 error
= udf_lookup_name_in_dir(dvp
, name
, namelen
,
752 DPRINTF(LOOKUP
, ("\tNOT found\n"));
754 * UGH, didn't find name. If we're creating or
755 * renaming on the last name this is OK and we ought
756 * to return EJUSTRETURN if its allowed to be created.
760 (nameiop
== CREATE
|| nameiop
== RENAME
))
763 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
);
765 /* keep the component name */
766 cnp
->cn_flags
|= SAVENAME
;
772 /* try to create/reuse the node */
773 error
= udf_get_node(ump
, &icb_loc
, &res_node
);
776 * If we are not at the last path component
777 * and found a non-directory or non-link entry
778 * (which may itself be pointing to a
779 * directory), raise an error.
781 vnodetp
= res_node
->vnode
->v_type
;
782 if ((vnodetp
!= VDIR
) && (vnodetp
!= VLNK
)) {
789 *vpp
= res_node
->vnode
;
796 * Store result in the cache if requested. If we are creating a file,
797 * the file might not be found and thus putting it into the namecache
798 * might be seen as negative caching.
800 if ((cnp
->cn_flags
& MAKEENTRY
) && nameiop
!= CREATE
)
801 cache_enter(dvp
, *vpp
, cnp
);
803 DPRINTFIF(LOOKUP
, error
, ("udf_lookup returing error %d\n", error
));
808 /* --------------------------------------------------------------------- */
813 struct vop_getattr_args
/* {
819 struct vnode
*vp
= ap
->a_vp
;
820 struct udf_node
*udf_node
= VTOI(vp
);
821 struct udf_mount
*ump
= udf_node
->ump
;
822 struct file_entry
*fe
= udf_node
->fe
;
823 struct extfile_entry
*efe
= udf_node
->efe
;
824 struct filetimes_extattr_entry
*ft_extattr
;
825 struct device_extattr_entry
*devattr
;
826 struct vattr
*vap
= ap
->a_vap
;
827 struct timestamp
*atime
, *mtime
, *attrtime
, *creatime
;
828 uint64_t filesize
, blkssize
;
830 uint32_t offset
, a_l
;
836 DPRINTF(CALL
, ("udf_getattr called\n"));
838 /* update times before we returning values */
839 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
841 /* get descriptor information */
843 nlink
= udf_rw16(fe
->link_cnt
);
844 uid
= (uid_t
)udf_rw32(fe
->uid
);
845 gid
= (gid_t
)udf_rw32(fe
->gid
);
846 filesize
= udf_rw64(fe
->inf_len
);
847 blkssize
= udf_rw64(fe
->logblks_rec
);
850 attrtime
= &fe
->attrtime
;
856 /* check our extended attribute if present */
857 error
= udf_extattr_search_intern(udf_node
,
858 UDF_FILETIMES_ATTR_NO
, "", &offset
, &a_l
);
860 ft_extattr
= (struct filetimes_extattr_entry
*)
862 if (ft_extattr
->existence
& UDF_FILETIMES_FILE_CREATION
)
863 creatime
= &ft_extattr
->times
[0];
866 assert(udf_node
->efe
);
867 nlink
= udf_rw16(efe
->link_cnt
);
868 uid
= (uid_t
)udf_rw32(efe
->uid
);
869 gid
= (gid_t
)udf_rw32(efe
->gid
);
870 filesize
= udf_rw64(efe
->inf_len
); /* XXX or obj_size? */
871 blkssize
= udf_rw64(efe
->logblks_rec
);
874 attrtime
= &efe
->attrtime
;
875 creatime
= &efe
->ctime
;
876 filedata
= efe
->data
;
879 /* do the uid/gid translation game */
880 if (uid
== (uid_t
) -1)
881 uid
= ump
->mount_args
.anon_uid
;
882 if (gid
== (gid_t
) -1)
883 gid
= ump
->mount_args
.anon_gid
;
885 /* fill in struct vattr with values from the node */
887 vap
->va_type
= vp
->v_type
;
888 vap
->va_mode
= udf_getaccessmode(udf_node
);
889 vap
->va_nlink
= nlink
;
892 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsidx
.__fsid_val
[0];
893 vap
->va_fileid
= udf_get_node_id(&udf_node
->loc
); /* inode hash XXX */
894 vap
->va_size
= filesize
;
895 vap
->va_blocksize
= udf_node
->ump
->discinfo
.sector_size
; /* wise? */
898 * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
899 * 1 to the link count if its a directory we're requested attributes
902 if (vap
->va_type
== VDIR
)
906 udf_timestamp_to_timespec(ump
, atime
, &vap
->va_atime
);
907 udf_timestamp_to_timespec(ump
, mtime
, &vap
->va_mtime
);
908 udf_timestamp_to_timespec(ump
, attrtime
, &vap
->va_ctime
);
909 udf_timestamp_to_timespec(ump
, creatime
, &vap
->va_birthtime
);
911 vap
->va_gen
= 1; /* no multiple generations yes (!?) */
912 vap
->va_flags
= 0; /* no flags */
913 vap
->va_bytes
= blkssize
* udf_node
->ump
->discinfo
.sector_size
;
914 vap
->va_filerev
= 1; /* TODO file revision numbers? */
916 /* TODO get vaflags from the extended attributes? */
918 if ((vap
->va_type
== VBLK
) || (vap
->va_type
== VCHR
)) {
919 error
= udf_extattr_search_intern(udf_node
,
920 UDF_DEVICESPEC_ATTR_NO
, "",
922 /* if error, deny access */
923 if (error
|| (filedata
== NULL
)) {
924 vap
->va_mode
= 0; /* or v_type = VNON? */
926 devattr
= (struct device_extattr_entry
*)
928 vap
->va_rdev
= makedev(
929 udf_rw32(devattr
->major
),
930 udf_rw32(devattr
->minor
)
932 /* TODO we could check the implementator */
939 /* --------------------------------------------------------------------- */
942 udf_chown(struct vnode
*vp
, uid_t new_uid
, gid_t new_gid
,
945 struct udf_node
*udf_node
= VTOI(vp
);
951 /* TODO get vaflags from the extended attributes? */
952 /* Immutable or append-only files cannot be modified, either. */
953 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
957 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
960 /* retrieve old values */
961 udf_getownership(udf_node
, &uid
, &gid
);
963 /* only one could be specified */
964 if (new_uid
== VNOVAL
)
966 if (new_gid
== VNOVAL
)
969 /* check if we can fit it in an 32 bits */
970 if ((uid_t
) ((uint32_t) new_uid
) != new_uid
)
972 if ((gid_t
) ((uint32_t) new_gid
) != new_gid
)
975 /* check permissions */
976 error
= genfs_can_chown(vp
, cred
, uid
, gid
, new_uid
, new_gid
);
980 /* change the ownership */
981 udf_setownership(udf_node
, new_uid
, new_gid
);
983 /* mark node changed */
984 udf_node
->i_flags
|= IN_CHANGE
;
991 udf_chmod(struct vnode
*vp
, mode_t mode
, kauth_cred_t cred
)
993 struct udf_node
*udf_node
= VTOI(vp
);
999 /* TODO get vaflags from the extended attributes? */
1000 /* Immutable or append-only files cannot be modified, either. */
1001 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
1005 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1008 /* retrieve uid/gid values */
1009 udf_getownership(udf_node
, &uid
, &gid
);
1011 /* check permissions */
1012 error
= genfs_can_chmod(vp
, cred
, uid
, gid
, mode
);
1017 udf_setaccessmode(udf_node
, mode
);
1019 /* mark node changed */
1020 udf_node
->i_flags
|= IN_CHANGE
;
1028 udf_chsize(struct vnode
*vp
, u_quad_t newsize
, kauth_cred_t cred
)
1030 struct udf_node
*udf_node
= VTOI(vp
);
1031 int error
, extended
;
1033 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1036 /* Decide whether this is a valid operation based on the file type. */
1037 switch (vp
->v_type
) {
1041 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1049 /* Allow modifications of special files even if in the file
1050 * system is mounted read-only (we are not modifying the
1051 * files themselves, but the objects they represent). */
1054 /* Anything else is unsupported. */
1059 /* TODO get vaflags from the extended attributes? */
1060 /* Immutable or append-only files cannot be modified, either. */
1061 if (node
->flags
& (IMMUTABLE
| APPEND
))
1065 /* resize file to the requested size */
1066 error
= udf_resize_node(udf_node
, newsize
, &extended
);
1070 udf_node
->i_flags
|= IN_CHANGE
| IN_MODIFY
;
1071 VN_KNOTE(vp
, NOTE_ATTRIB
| (extended
? NOTE_EXTEND
: 0));
1072 udf_update(vp
, NULL
, NULL
, NULL
, 0);
1080 udf_chflags(struct vnode
*vp
, mode_t mode
, kauth_cred_t cred
)
1082 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1085 /* XXX we can't do this yet, but erroring out is enoying XXX */
1092 udf_chtimes(struct vnode
*vp
,
1093 struct timespec
*atime
, struct timespec
*mtime
,
1094 struct timespec
*birthtime
, int setattrflags
,
1097 struct udf_node
*udf_node
= VTOI(vp
);
1103 /* TODO get vaflags from the extended attributes? */
1104 /* Immutable or append-only files cannot be modified, either. */
1105 if (udf_node
->flags
& (IMMUTABLE
| APPEND
))
1109 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1112 /* retrieve uid/gid values */
1113 udf_getownership(udf_node
, &uid
, &gid
);
1115 /* check permissions */
1116 error
= genfs_can_chtimes(vp
, setattrflags
, uid
, cred
);
1120 /* update node flags depending on what times are passed */
1121 if (atime
->tv_sec
!= VNOVAL
)
1122 if (!(vp
->v_mount
->mnt_flag
& MNT_NOATIME
))
1123 udf_node
->i_flags
|= IN_ACCESS
;
1124 if ((mtime
->tv_sec
!= VNOVAL
) || (birthtime
->tv_sec
!= VNOVAL
))
1125 udf_node
->i_flags
|= IN_CHANGE
| IN_UPDATE
;
1127 return udf_update(vp
, atime
, mtime
, birthtime
, 0);
1132 udf_setattr(void *v
)
1134 struct vop_setattr_args
/* {
1136 struct vattr *a_vap;
1137 kauth_cred_t a_cred;
1140 struct vnode
*vp
= ap
->a_vp
;
1141 /* struct udf_node *udf_node = VTOI(vp); */
1142 /* struct udf_mount *ump = udf_node->ump; */
1143 kauth_cred_t cred
= ap
->a_cred
;
1144 struct vattr
*vap
= ap
->a_vap
;
1147 DPRINTF(CALL
, ("udf_setattr called\n"));
1149 /* Abort if any unsettable attribute is given. */
1151 if (vap
->va_type
!= VNON
||
1152 vap
->va_nlink
!= VNOVAL
||
1153 vap
->va_fsid
!= VNOVAL
||
1154 vap
->va_fileid
!= VNOVAL
||
1155 vap
->va_blocksize
!= VNOVAL
||
1157 /* checks are debated */
1158 vap
->va_ctime
.tv_sec
!= VNOVAL
||
1159 vap
->va_ctime
.tv_nsec
!= VNOVAL
||
1160 vap
->va_birthtime
.tv_sec
!= VNOVAL
||
1161 vap
->va_birthtime
.tv_nsec
!= VNOVAL
||
1163 vap
->va_gen
!= VNOVAL
||
1164 vap
->va_rdev
!= VNOVAL
||
1165 vap
->va_bytes
!= VNOVAL
)
1168 DPRINTF(ATTR
, ("setattr changing:\n"));
1169 if (error
== 0 && (vap
->va_flags
!= VNOVAL
)) {
1170 DPRINTF(ATTR
, ("\tchflags\n"));
1171 error
= udf_chflags(vp
, vap
->va_flags
, cred
);
1174 if (error
== 0 && (vap
->va_size
!= VNOVAL
)) {
1175 DPRINTF(ATTR
, ("\tchsize\n"));
1176 error
= udf_chsize(vp
, vap
->va_size
, cred
);
1179 if (error
== 0 && (vap
->va_uid
!= VNOVAL
|| vap
->va_gid
!= VNOVAL
)) {
1180 DPRINTF(ATTR
, ("\tchown\n"));
1181 error
= udf_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
);
1184 if (error
== 0 && (vap
->va_mode
!= VNOVAL
)) {
1185 DPRINTF(ATTR
, ("\tchmod\n"));
1186 error
= udf_chmod(vp
, vap
->va_mode
, cred
);
1190 ((vap
->va_atime
.tv_sec
!= VNOVAL
&&
1191 vap
->va_atime
.tv_nsec
!= VNOVAL
) ||
1192 (vap
->va_mtime
.tv_sec
!= VNOVAL
&&
1193 vap
->va_mtime
.tv_nsec
!= VNOVAL
))
1195 DPRINTF(ATTR
, ("\tchtimes\n"));
1196 error
= udf_chtimes(vp
, &vap
->va_atime
, &vap
->va_mtime
,
1197 &vap
->va_birthtime
, vap
->va_vaflags
, cred
);
1199 VN_KNOTE(vp
, NOTE_ATTRIB
);
1204 /* --------------------------------------------------------------------- */
1207 * Return POSIX pathconf information for UDF file systems.
1210 udf_pathconf(void *v
)
1212 struct vop_pathconf_args
/* {
1215 register_t *a_retval;
1219 DPRINTF(CALL
, ("udf_pathconf called\n"));
1221 switch (ap
->a_name
) {
1223 *ap
->a_retval
= (1<<16)-1; /* 16 bits */
1226 *ap
->a_retval
= NAME_MAX
;
1229 *ap
->a_retval
= PATH_MAX
;
1232 *ap
->a_retval
= PIPE_BUF
;
1234 case _PC_CHOWN_RESTRICTED
:
1241 *ap
->a_retval
= 0; /* synchronised is off for performance */
1243 case _PC_FILESIZEBITS
:
1244 /* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */
1245 bits
= 64; /* XXX ought to deliver 65 */
1248 bits
= 64 * vp
->v_mount
->mnt_dev_bshift
;
1250 *ap
->a_retval
= bits
;
1258 /* --------------------------------------------------------------------- */
1263 struct vop_open_args
/* {
1266 kauth_cred_t a_cred;
1271 DPRINTF(CALL
, ("udf_open called\n"));
1274 * Files marked append-only must be opened for appending.
1275 * TODO: get chflags(2) flags from extened attribute.
1278 if ((flags
& APPEND
) && (ap
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)
1285 /* --------------------------------------------------------------------- */
1290 struct vop_close_args
/* {
1293 kauth_cred_t a_cred;
1296 struct vnode
*vp
= ap
->a_vp
;
1297 struct udf_node
*udf_node
= VTOI(vp
);
1298 int async
= vp
->v_mount
->mnt_flag
& MNT_ASYNC
;
1301 DPRINTF(CALL
, ("udf_close called\n"));
1302 udf_node
= udf_node
; /* shut up gcc */
1304 if (!async
&& (vp
->v_type
!= VDIR
)) {
1305 mutex_enter(&vp
->v_interlock
);
1306 error
= VOP_PUTPAGES(vp
, 0, 0, PGO_CLEANIT
);
1311 mutex_enter(&vp
->v_interlock
);
1312 if (vp
->v_usecount
> 1)
1313 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
1314 mutex_exit(&vp
->v_interlock
);
1320 /* --------------------------------------------------------------------- */
1323 udf_check_possible(struct vnode
*vp
, struct vattr
*vap
, mode_t mode
)
1327 /* check if we are allowed to write */
1328 switch (vap
->va_type
) {
1333 * normal nodes: check if we're on a read-only mounted
1334 * filingsystem and bomb out if we're trying to write.
1336 if ((mode
& VWRITE
) && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
))
1344 * special nodes: even on read-only mounted filingsystems
1345 * these are allowed to be written to if permissions allow.
1349 /* no idea what this is */
1353 /* noone may write immutable files */
1354 /* TODO: get chflags(2) flags from extened attribute. */
1356 if ((mode
& VWRITE
) && (flags
& IMMUTABLE
))
1363 udf_check_permitted(struct vnode
*vp
, struct vattr
*vap
, mode_t mode
,
1367 /* ask the generic genfs_can_access to advice on security */
1368 return genfs_can_access(vp
->v_type
,
1369 vap
->va_mode
, vap
->va_uid
, vap
->va_gid
,
1376 struct vop_access_args
/* {
1379 kauth_cred_t a_cred;
1382 struct vnode
*vp
= ap
->a_vp
;
1383 mode_t mode
= ap
->a_mode
;
1384 kauth_cred_t cred
= ap
->a_cred
;
1385 /* struct udf_node *udf_node = VTOI(vp); */
1389 DPRINTF(CALL
, ("udf_access called\n"));
1391 error
= VOP_GETATTR(vp
, &vap
, NULL
);
1395 error
= udf_check_possible(vp
, &vap
, mode
);
1399 error
= udf_check_permitted(vp
, &vap
, mode
, cred
);
1404 /* --------------------------------------------------------------------- */
1409 struct vop_create_args
/* {
1410 struct vnode *a_dvp;
1411 struct vnode **a_vpp;
1412 struct componentname *a_cnp;
1413 struct vattr *a_vap;
1415 struct vnode
*dvp
= ap
->a_dvp
;
1416 struct vnode
**vpp
= ap
->a_vpp
;
1417 struct vattr
*vap
= ap
->a_vap
;
1418 struct componentname
*cnp
= ap
->a_cnp
;
1421 DPRINTF(CALL
, ("udf_create called\n"));
1422 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1424 if (error
|| !(cnp
->cn_flags
& SAVESTART
))
1425 PNBUF_PUT(cnp
->cn_pnbuf
);
1430 /* --------------------------------------------------------------------- */
1435 struct vop_mknod_args
/* {
1436 struct vnode *a_dvp;
1437 struct vnode **a_vpp;
1438 struct componentname *a_cnp;
1439 struct vattr *a_vap;
1441 struct vnode
*dvp
= ap
->a_dvp
;
1442 struct vnode
**vpp
= ap
->a_vpp
;
1443 struct vattr
*vap
= ap
->a_vap
;
1444 struct componentname
*cnp
= ap
->a_cnp
;
1447 DPRINTF(CALL
, ("udf_mknod called\n"));
1448 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1450 if (error
|| !(cnp
->cn_flags
& SAVESTART
))
1451 PNBUF_PUT(cnp
->cn_pnbuf
);
1456 /* --------------------------------------------------------------------- */
1461 struct vop_mkdir_args
/* {
1462 struct vnode *a_dvp;
1463 struct vnode **a_vpp;
1464 struct componentname *a_cnp;
1465 struct vattr *a_vap;
1467 struct vnode
*dvp
= ap
->a_dvp
;
1468 struct vnode
**vpp
= ap
->a_vpp
;
1469 struct vattr
*vap
= ap
->a_vap
;
1470 struct componentname
*cnp
= ap
->a_cnp
;
1473 DPRINTF(CALL
, ("udf_mkdir called\n"));
1474 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1476 if (error
|| !(cnp
->cn_flags
& SAVESTART
))
1477 PNBUF_PUT(cnp
->cn_pnbuf
);
1482 /* --------------------------------------------------------------------- */
1485 udf_do_link(struct vnode
*dvp
, struct vnode
*vp
, struct componentname
*cnp
)
1487 struct udf_node
*udf_node
, *dir_node
;
1491 DPRINTF(CALL
, ("udf_link called\n"));
1494 /* some quick checks */
1495 if (vp
->v_type
== VDIR
)
1496 return EPERM
; /* can't link a directory */
1497 if (dvp
->v_mount
!= vp
->v_mount
)
1498 return EXDEV
; /* can't link across devices */
1500 return EPERM
; /* can't be the same */
1503 error
= vn_lock(vp
, LK_EXCLUSIVE
);
1507 /* get attributes */
1508 dir_node
= VTOI(dvp
);
1509 udf_node
= VTOI(vp
);
1511 error
= VOP_GETATTR(vp
, &vap
, FSCRED
);
1515 /* check link count overflow */
1516 if (vap
.va_nlink
>= (1<<16)-1) /* uint16_t */
1519 return udf_dir_attach(dir_node
->ump
, dir_node
, udf_node
, &vap
, cnp
);
1525 struct vop_link_args
/* {
1526 struct vnode *a_dvp;
1528 struct componentname *a_cnp;
1530 struct vnode
*dvp
= ap
->a_dvp
;
1531 struct vnode
*vp
= ap
->a_vp
;
1532 struct componentname
*cnp
= ap
->a_cnp
;
1535 error
= udf_do_link(dvp
, vp
, cnp
);
1537 VOP_ABORTOP(dvp
, cnp
);
1539 if ((vp
!= dvp
) && (VOP_ISLOCKED(vp
) == LK_EXCLUSIVE
))
1542 VN_KNOTE(vp
, NOTE_LINK
);
1543 VN_KNOTE(dvp
, NOTE_WRITE
);
1549 /* --------------------------------------------------------------------- */
1552 udf_do_symlink(struct udf_node
*udf_node
, char *target
)
1554 struct pathcomp pathcomp
;
1555 uint8_t *pathbuf
, *pathpos
, *compnamepos
;
1557 int pathlen
, len
, compnamelen
, mntonnamelen
;
1560 /* process `target' to an UDF structure */
1561 pathbuf
= malloc(UDF_SYMLINKBUFLEN
, M_UDFTEMP
, M_WAITOK
);
1565 if (*target
== '/') {
1566 /* symlink starts from the root */
1567 len
= UDF_PATH_COMP_SIZE
;
1568 memset(&pathcomp
, 0, len
);
1569 pathcomp
.type
= UDF_PATH_COMP_ROOT
;
1571 /* check if its mount-point relative! */
1572 mntonname
= udf_node
->ump
->vfs_mountp
->mnt_stat
.f_mntonname
;
1573 mntonnamelen
= strlen(mntonname
);
1574 if (strlen(target
) >= mntonnamelen
) {
1575 if (strncmp(target
, mntonname
, mntonnamelen
) == 0) {
1576 pathcomp
.type
= UDF_PATH_COMP_MOUNTROOT
;
1577 target
+= mntonnamelen
;
1583 memcpy(pathpos
, &pathcomp
, len
);
1590 /* ignore multiple '/' */
1591 while (*target
== '/') {
1597 /* extract component name */
1599 compnamepos
= target
;
1600 while ((*target
) && (*target
!= '/')) {
1605 /* just trunc if too long ?? (security issue) */
1606 if (compnamelen
>= 127) {
1607 error
= ENAMETOOLONG
;
1611 /* convert unix name to UDF name */
1612 len
= sizeof(struct pathcomp
);
1613 memset(&pathcomp
, 0, len
);
1614 pathcomp
.type
= UDF_PATH_COMP_NAME
;
1615 len
= UDF_PATH_COMP_SIZE
;
1617 if ((compnamelen
== 2) && (strncmp(compnamepos
, "..", 2) == 0))
1618 pathcomp
.type
= UDF_PATH_COMP_PARENTDIR
;
1619 if ((compnamelen
== 1) && (*compnamepos
== '.'))
1620 pathcomp
.type
= UDF_PATH_COMP_CURDIR
;
1622 if (pathcomp
.type
== UDF_PATH_COMP_NAME
) {
1624 (char *) &pathcomp
.ident
, &pathcomp
.l_ci
,
1625 compnamepos
, compnamelen
,
1626 &udf_node
->ump
->logical_vol
->desc_charset
);
1627 len
= UDF_PATH_COMP_SIZE
+ pathcomp
.l_ci
;
1630 if (pathlen
+ len
>= UDF_SYMLINKBUFLEN
) {
1631 error
= ENAMETOOLONG
;
1635 memcpy(pathpos
, &pathcomp
, len
);
1641 /* aparently too big */
1642 free(pathbuf
, M_UDFTEMP
);
1646 error
= udf_grow_node(udf_node
, pathlen
);
1648 /* failed to pregrow node */
1649 free(pathbuf
, M_UDFTEMP
);
1653 /* write out structure on the new file */
1654 error
= vn_rdwr(UIO_WRITE
, udf_node
->vnode
,
1655 pathbuf
, pathlen
, 0,
1656 UIO_SYSSPACE
, IO_NODELOCKED
| IO_ALTSEMANTICS
,
1657 FSCRED
, NULL
, NULL
);
1659 /* return status of symlink contents writeout */
1660 free(pathbuf
, M_UDFTEMP
);
1666 udf_symlink(void *v
)
1668 struct vop_symlink_args
/* {
1669 struct vnode *a_dvp;
1670 struct vnode **a_vpp;
1671 struct componentname *a_cnp;
1672 struct vattr *a_vap;
1675 struct vnode
*dvp
= ap
->a_dvp
;
1676 struct vnode
**vpp
= ap
->a_vpp
;
1677 struct vattr
*vap
= ap
->a_vap
;
1678 struct componentname
*cnp
= ap
->a_cnp
;
1679 struct udf_node
*dir_node
;
1680 struct udf_node
*udf_node
;
1683 DPRINTF(CALL
, ("udf_symlink called\n"));
1684 DPRINTF(CALL
, ("\tlinking to `%s`\n", ap
->a_target
));
1685 error
= udf_create_node(dvp
, vpp
, vap
, cnp
);
1686 KASSERT(((error
== 0) && (*vpp
!= NULL
)) || ((error
&& (*vpp
== NULL
))));
1688 dir_node
= VTOI(dvp
);
1689 udf_node
= VTOI(*vpp
);
1691 error
= udf_do_symlink(udf_node
, ap
->a_target
);
1694 udf_shrink_node(udf_node
, 0);
1695 udf_dir_detach(udf_node
->ump
, dir_node
, udf_node
, cnp
);
1698 if (error
|| !(cnp
->cn_flags
& SAVESTART
))
1699 PNBUF_PUT(cnp
->cn_pnbuf
);
1704 /* --------------------------------------------------------------------- */
1707 udf_readlink(void *v
)
1709 struct vop_readlink_args
/* {
1712 kauth_cred_t a_cred;
1714 struct vnode
*vp
= ap
->a_vp
;
1715 struct uio
*uio
= ap
->a_uio
;
1716 kauth_cred_t cred
= ap
->a_cred
;
1717 struct udf_node
*udf_node
;
1718 struct pathcomp pathcomp
;
1720 uint8_t *pathbuf
, *targetbuf
, *tmpname
;
1721 uint8_t *pathpos
, *targetpos
;
1723 int pathlen
, targetlen
, namelen
, mntonnamelen
, len
, l_ci
;
1726 DPRINTF(CALL
, ("udf_readlink called\n"));
1728 udf_node
= VTOI(vp
);
1729 error
= VOP_GETATTR(vp
, &vattr
, cred
);
1733 /* claim temporary buffers for translation */
1734 pathbuf
= malloc(UDF_SYMLINKBUFLEN
, M_UDFTEMP
, M_WAITOK
);
1735 targetbuf
= malloc(PATH_MAX
+1, M_UDFTEMP
, M_WAITOK
);
1736 tmpname
= malloc(PATH_MAX
+1, M_UDFTEMP
, M_WAITOK
);
1737 memset(pathbuf
, 0, UDF_SYMLINKBUFLEN
);
1738 memset(targetbuf
, 0, PATH_MAX
);
1740 /* read contents of file in our temporary buffer */
1741 error
= vn_rdwr(UIO_READ
, udf_node
->vnode
,
1742 pathbuf
, vattr
.va_size
, 0,
1743 UIO_SYSSPACE
, IO_NODELOCKED
| IO_ALTSEMANTICS
,
1744 FSCRED
, NULL
, NULL
);
1746 /* failed to read in symlink contents */
1747 free(pathbuf
, M_UDFTEMP
);
1748 free(targetbuf
, M_UDFTEMP
);
1749 free(tmpname
, M_UDFTEMP
);
1753 /* convert to a unix path */
1756 targetpos
= targetbuf
;
1757 targetlen
= PATH_MAX
;
1758 mntonname
= udf_node
->ump
->vfs_mountp
->mnt_stat
.f_mntonname
;
1759 mntonnamelen
= strlen(mntonname
);
1763 while (vattr
.va_size
- pathlen
>= UDF_PATH_COMP_SIZE
) {
1764 len
= UDF_PATH_COMP_SIZE
;
1765 memcpy(&pathcomp
, pathpos
, len
);
1766 l_ci
= pathcomp
.l_ci
;
1767 switch (pathcomp
.type
) {
1768 case UDF_PATH_COMP_ROOT
:
1769 /* XXX should check for l_ci; bugcompatible now */
1770 if ((targetlen
< 1) || !first
) {
1774 *targetpos
++ = '/'; targetlen
--;
1776 case UDF_PATH_COMP_MOUNTROOT
:
1777 /* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */
1778 if (l_ci
|| (targetlen
< mntonnamelen
+1) || !first
) {
1782 memcpy(targetpos
, mntonname
, mntonnamelen
);
1783 targetpos
+= mntonnamelen
; targetlen
-= mntonnamelen
;
1784 if (vattr
.va_size
-pathlen
> UDF_PATH_COMP_SIZE
+l_ci
) {
1785 /* more follows, so must be directory */
1786 *targetpos
++ = '/'; targetlen
--;
1789 case UDF_PATH_COMP_PARENTDIR
:
1790 /* XXX should check for l_ci; bugcompatible now */
1791 if (targetlen
< 3) {
1795 *targetpos
++ = '.'; targetlen
--;
1796 *targetpos
++ = '.'; targetlen
--;
1797 *targetpos
++ = '/'; targetlen
--;
1799 case UDF_PATH_COMP_CURDIR
:
1800 /* XXX should check for l_ci; bugcompatible now */
1801 if (targetlen
< 2) {
1805 *targetpos
++ = '.'; targetlen
--;
1806 *targetpos
++ = '/'; targetlen
--;
1808 case UDF_PATH_COMP_NAME
:
1813 memset(tmpname
, 0, PATH_MAX
);
1814 memcpy(&pathcomp
, pathpos
, len
+ l_ci
);
1815 udf_to_unix_name(tmpname
, MAXPATHLEN
,
1816 pathcomp
.ident
, l_ci
,
1817 &udf_node
->ump
->logical_vol
->desc_charset
);
1818 namelen
= strlen(tmpname
);
1819 if (targetlen
< namelen
+ 1) {
1823 memcpy(targetpos
, tmpname
, namelen
);
1824 targetpos
+= namelen
; targetlen
-= namelen
;
1825 if (vattr
.va_size
-pathlen
> UDF_PATH_COMP_SIZE
+l_ci
) {
1826 /* more follows, so must be directory */
1827 *targetpos
++ = '/'; targetlen
--;
1837 pathpos
+= UDF_PATH_COMP_SIZE
+ l_ci
;
1838 pathlen
+= UDF_PATH_COMP_SIZE
+ l_ci
;
1841 /* all processed? */
1842 if (vattr
.va_size
- pathlen
> 0)
1845 /* uiomove() to destination */
1847 uiomove(targetbuf
, PATH_MAX
- targetlen
, uio
);
1849 free(pathbuf
, M_UDFTEMP
);
1850 free(targetbuf
, M_UDFTEMP
);
1851 free(tmpname
, M_UDFTEMP
);
1856 /* --------------------------------------------------------------------- */
1859 * Check if source directory is in the path of the target directory. Target
1860 * is supplied locked, source is unlocked. The target is always vput before
1861 * returning. Modeled after UFS.
1863 * If source is on the path from target to the root, return error.
1867 udf_on_rootpath(struct udf_node
*source
, struct udf_node
*target
)
1869 struct udf_mount
*ump
= target
->ump
;
1870 struct udf_node
*res_node
;
1871 struct long_ad icb_loc
, *root_icb
;
1881 root_icb
= &ump
->fileset_desc
->rootdir_icb
;
1883 /* if nodes are equal, it is no use looking */
1884 if (udf_compare_icb(&source
->loc
, &target
->loc
) == 0) {
1889 /* nothing can exist before the root */
1890 if (udf_compare_icb(root_icb
, &target
->loc
) == 0) {
1896 DPRINTF(NODE
, ("udf_on_rootpath : "
1897 "source vp %p, looking at vp %p\n",
1898 source
->vnode
, res_node
->vnode
));
1901 if (res_node
->vnode
->v_type
!= VDIR
) {
1906 /* go down one level */
1907 error
= udf_lookup_name_in_dir(res_node
->vnode
, name
, namelen
,
1909 DPRINTF(NODE
, ("\tlookup of '..' resulted in error %d, "
1910 "found %d\n", error
, found
));
1917 /* did we encounter source node? */
1918 if (udf_compare_icb(&icb_loc
, &source
->loc
) == 0) {
1923 /* did we encounter the root node? */
1924 if (udf_compare_icb(&icb_loc
, root_icb
) == 0) {
1929 /* push our intermediate node, we're done with it */
1930 /* DPRINTF(NODE, ("\tvput %p\n", target->vnode)); */
1931 vput(res_node
->vnode
);
1933 DPRINTF(NODE
, ("\tgetting the .. node\n"));
1934 error
= udf_get_node(ump
, &icb_loc
, &res_node
);
1936 if (error
) { /* argh, bail out */
1937 KASSERT(res_node
== NULL
);
1943 DPRINTF(NODE
, ("\tresult: %svalid, error = %d\n", error
?"in":"", error
));
1945 /* put our last node */
1947 vput(res_node
->vnode
);
1952 /* note: i tried to follow the logics of the tmpfs rename code */
1956 struct vop_rename_args
/* {
1957 struct vnode *a_fdvp;
1958 struct vnode *a_fvp;
1959 struct componentname *a_fcnp;
1960 struct vnode *a_tdvp;
1961 struct vnode *a_tvp;
1962 struct componentname *a_tcnp;
1964 struct vnode
*tvp
= ap
->a_tvp
;
1965 struct vnode
*tdvp
= ap
->a_tdvp
;
1966 struct vnode
*fvp
= ap
->a_fvp
;
1967 struct vnode
*fdvp
= ap
->a_fdvp
;
1968 struct componentname
*tcnp
= ap
->a_tcnp
;
1969 struct componentname
*fcnp
= ap
->a_fcnp
;
1970 struct udf_node
*fnode
, *fdnode
, *tnode
, *tdnode
;
1971 struct vattr fvap
, tvap
;
1974 DPRINTF(CALL
, ("udf_rename called\n"));
1976 /* disallow cross-device renames */
1977 if (fvp
->v_mount
!= tdvp
->v_mount
||
1978 (tvp
!= NULL
&& fvp
->v_mount
!= tvp
->v_mount
)) {
1984 fdnode
= VTOI(fdvp
);
1985 tnode
= (tvp
== NULL
) ? NULL
: VTOI(tvp
);
1986 tdnode
= VTOI(tdvp
);
1988 /* lock our source dir */
1989 if (fdnode
!= tdnode
) {
1990 error
= vn_lock(fdvp
, LK_EXCLUSIVE
| LK_RETRY
);
1995 /* get info about the node to be moved */
1996 error
= VOP_GETATTR(fvp
, &fvap
, FSCRED
);
1997 KASSERT(error
== 0);
1999 /* check when to delete the old already existing entry */
2001 /* get info about the node to be moved to */
2002 error
= VOP_GETATTR(fvp
, &tvap
, FSCRED
);
2003 KASSERT(error
== 0);
2005 /* if both dirs, make sure the destination is empty */
2006 if (fvp
->v_type
== VDIR
&& tvp
->v_type
== VDIR
) {
2007 if (tvap
.va_nlink
> 2) {
2012 /* if moving dir, make sure destination is dir too */
2013 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2017 /* if we're moving a non-directory, make sure dest is no dir */
2018 if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2024 /* check if moving a directory to a new parent is allowed */
2025 if ((fdnode
!= tdnode
) && (fvp
->v_type
== VDIR
)) {
2026 /* release tvp since we might encounter it and lock up */
2030 /* vref tdvp since we lose its ref in udf_on_rootpath */
2033 /* search if fnode is a component of tdnode's path to root */
2034 error
= udf_on_rootpath(fnode
, tdnode
);
2036 DPRINTF(NODE
, ("Dir rename allowed ? %s\n", error
? "NO":"YES"));
2039 /* compensate for our vref earlier */
2044 /* relock tdvp; its still here due to the vref earlier */
2045 vn_lock(tdvp
, LK_EXCLUSIVE
| LK_RETRY
);
2048 * re-lookup tvp since the parent has been unlocked, so could
2049 * have changed/removed in the meantime.
2051 tcnp
->cn_flags
&= ~SAVESTART
;
2052 error
= relookup(tdvp
, &tvp
, tcnp
);
2057 tnode
= (tvp
== NULL
) ? NULL
: VTOI(tvp
);
2060 /* remove existing entry if present */
2062 udf_dir_detach(tdnode
->ump
, tdnode
, tnode
, tcnp
);
2064 /* create new directory entry for the node */
2065 error
= udf_dir_attach(tdnode
->ump
, tdnode
, fnode
, &fvap
, tcnp
);
2069 /* unlink old directory entry for the node, if failing, unattach new */
2070 error
= udf_dir_detach(tdnode
->ump
, fdnode
, fnode
, fcnp
);
2072 udf_dir_detach(tdnode
->ump
, tdnode
, fnode
, tcnp
);
2076 /* update tnode's '..' if moving directory to new parent */
2077 if ((fdnode
!= tdnode
) && (fvp
->v_type
== VDIR
)) {
2078 /* update fnode's '..' entry */
2079 error
= udf_dir_update_rootentry(fnode
->ump
, fnode
, tdnode
);
2081 /* 'try' to recover from this situation */
2082 udf_dir_attach(tdnode
->ump
, fdnode
, fnode
, &fvap
, fcnp
);
2083 udf_dir_detach(tdnode
->ump
, tdnode
, fnode
, tcnp
);
2088 if (fdnode
!= tdnode
)
2089 VOP_UNLOCK(fdvp
, 0);
2092 VOP_ABORTOP(tdvp
, tcnp
);
2099 VOP_ABORTOP(fdvp
, fcnp
);
2101 /* release source nodes. */
2108 /* --------------------------------------------------------------------- */
2113 struct vop_remove_args
/* {
2114 struct vnode *a_dvp;
2116 struct componentname *a_cnp;
2118 struct vnode
*dvp
= ap
->a_dvp
;
2119 struct vnode
*vp
= ap
->a_vp
;
2120 struct componentname
*cnp
= ap
->a_cnp
;
2121 struct udf_node
*dir_node
= VTOI(dvp
);
2122 struct udf_node
*udf_node
= VTOI(vp
);
2123 struct udf_mount
*ump
= dir_node
->ump
;
2126 DPRINTF(CALL
, ("udf_remove called\n"));
2127 if (vp
->v_type
!= VDIR
) {
2128 error
= udf_dir_detach(ump
, dir_node
, udf_node
, cnp
);
2129 DPRINTFIF(NODE
, error
, ("\tgot error removing file\n"));
2131 DPRINTF(NODE
, ("\tis a directory: perm. denied\n"));
2136 VN_KNOTE(vp
, NOTE_DELETE
);
2137 VN_KNOTE(dvp
, NOTE_WRITE
);
2149 /* --------------------------------------------------------------------- */
2154 struct vop_rmdir_args
/* {
2155 struct vnode *a_dvp;
2157 struct componentname *a_cnp;
2159 struct vnode
*vp
= ap
->a_vp
;
2160 struct vnode
*dvp
= ap
->a_dvp
;
2161 struct componentname
*cnp
= ap
->a_cnp
;
2162 struct udf_node
*dir_node
= VTOI(dvp
);
2163 struct udf_node
*udf_node
= VTOI(vp
);
2164 struct udf_mount
*ump
= dir_node
->ump
;
2167 DPRINTF(NOTIMPL
, ("udf_rmdir called\n"));
2169 /* don't allow '.' to be deleted */
2170 if (dir_node
== udf_node
) {
2176 /* check to see if the directory is empty */
2179 refcnt
= udf_rw16(udf_node
->fe
->link_cnt
);
2181 refcnt
= udf_rw16(udf_node
->efe
->link_cnt
);
2190 /* detach the node from the directory */
2191 error
= udf_dir_detach(ump
, dir_node
, udf_node
, cnp
);
2194 // cache_purge(dvp); /* XXX from msdosfs, why? */
2195 VN_KNOTE(vp
, NOTE_DELETE
);
2197 DPRINTFIF(NODE
, error
, ("\tgot error removing file\n"));
2199 /* unput the nodes and exit */
2206 /* --------------------------------------------------------------------- */
2211 struct vop_fsync_args
/* {
2213 kauth_cred_t a_cred;
2219 struct vnode
*vp
= ap
->a_vp
;
2220 struct udf_node
*udf_node
= VTOI(vp
);
2221 int error
, flags
, wait
;
2223 DPRINTF(SYNC
, ("udf_fsync called on %p : %s, %s\n",
2225 (ap
->a_flags
& FSYNC_WAIT
) ? "wait":"no wait",
2226 (ap
->a_flags
& FSYNC_DATAONLY
) ? "data_only":"complete"));
2228 /* flush data and wait for it when requested */
2229 wait
= (ap
->a_flags
& FSYNC_WAIT
) ? UPDATE_WAIT
: 0;
2230 vflushbuf(vp
, wait
);
2232 if (udf_node
== NULL
) {
2233 printf("udf_fsync() called on NULL udf_node!\n");
2236 if (vp
->v_tag
!= VT_UDF
) {
2237 printf("udf_fsync() called on node not tagged as UDF node!\n");
2242 udf_itimes(udf_node
, NULL
, NULL
, NULL
);
2244 /* if called when mounted readonly, never write back */
2245 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
2248 /* if only data is requested, return */
2249 if (ap
->a_flags
& FSYNC_DATAONLY
)
2252 /* check if the node is dirty 'enough'*/
2253 flags
= udf_node
->i_flags
& (IN_MODIFIED
| IN_ACCESSED
);
2257 /* if we don't have to wait, check for IO pending */
2259 if (vp
->v_numoutput
> 0) {
2260 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on v_numoutput\n", udf_node
));
2263 if (udf_node
->outstanding_bufs
> 0) {
2264 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on outstanding_bufs\n", udf_node
));
2267 if (udf_node
->outstanding_nodedscr
> 0) {
2268 DPRINTF(SYNC
, ("udf_fsync %p, rejecting on outstanding_nodedscr\n", udf_node
));
2273 /* wait until vp->v_numoutput reaches zero i.e. is finished */
2275 DPRINTF(SYNC
, ("udf_fsync %p, waiting\n", udf_node
));
2276 mutex_enter(&vp
->v_interlock
);
2277 while (vp
->v_numoutput
) {
2278 DPRINTF(SYNC
, ("udf_fsync %p, v_numoutput %d\n", udf_node
, vp
->v_numoutput
));
2279 cv_timedwait(&vp
->v_cv
, &vp
->v_interlock
, hz
/8);
2281 mutex_exit(&vp
->v_interlock
);
2282 DPRINTF(SYNC
, ("udf_fsync %p, fin wait\n", udf_node
));
2285 /* write out node and wait for it if requested */
2286 DPRINTF(SYNC
, ("udf_fsync %p, writeout node\n", udf_node
));
2287 error
= udf_writeout_node(udf_node
, wait
);
2291 /* TODO/XXX if ap->a_flags & FSYNC_CACHE, we ought to do a disc sync */
2296 /* --------------------------------------------------------------------- */
2299 udf_advlock(void *v
)
2301 struct vop_advlock_args
/* {
2308 struct vnode
*vp
= ap
->a_vp
;
2309 struct udf_node
*udf_node
= VTOI(vp
);
2310 struct file_entry
*fe
;
2311 struct extfile_entry
*efe
;
2314 DPRINTF(LOCKING
, ("udf_advlock called\n"));
2316 /* get directory filesize */
2319 file_size
= udf_rw64(fe
->inf_len
);
2321 assert(udf_node
->efe
);
2322 efe
= udf_node
->efe
;
2323 file_size
= udf_rw64(efe
->inf_len
);
2326 return lf_advlock(ap
, &udf_node
->lockf
, file_size
);
2329 /* --------------------------------------------------------------------- */
2331 /* Global vfs vnode data structures for udfs */
2332 int (**udf_vnodeop_p
)(void *);
2334 const struct vnodeopv_entry_desc udf_vnodeop_entries
[] = {
2335 { &vop_default_desc
, vn_default_error
},
2336 { &vop_lookup_desc
, udf_lookup
}, /* lookup */
2337 { &vop_create_desc
, udf_create
}, /* create */
2338 { &vop_mknod_desc
, udf_mknod
}, /* mknod */ /* TODO */
2339 { &vop_open_desc
, udf_open
}, /* open */
2340 { &vop_close_desc
, udf_close
}, /* close */
2341 { &vop_access_desc
, udf_access
}, /* access */
2342 { &vop_getattr_desc
, udf_getattr
}, /* getattr */
2343 { &vop_setattr_desc
, udf_setattr
}, /* setattr */ /* TODO chflags */
2344 { &vop_read_desc
, udf_read
}, /* read */
2345 { &vop_write_desc
, udf_write
}, /* write */ /* WRITE */
2346 { &vop_fcntl_desc
, genfs_fcntl
}, /* fcntl */ /* TODO? */
2347 { &vop_ioctl_desc
, genfs_enoioctl
}, /* ioctl */ /* TODO? */
2348 { &vop_poll_desc
, genfs_poll
}, /* poll */ /* TODO/OK? */
2349 { &vop_kqfilter_desc
, genfs_kqfilter
}, /* kqfilter */ /* ? */
2350 { &vop_revoke_desc
, genfs_revoke
}, /* revoke */ /* TODO? */
2351 { &vop_mmap_desc
, genfs_mmap
}, /* mmap */ /* OK? */
2352 { &vop_fsync_desc
, udf_fsync
}, /* fsync */
2353 { &vop_seek_desc
, genfs_seek
}, /* seek */
2354 { &vop_remove_desc
, udf_remove
}, /* remove */
2355 { &vop_link_desc
, udf_link
}, /* link */ /* TODO */
2356 { &vop_rename_desc
, udf_rename
}, /* rename */ /* TODO */
2357 { &vop_mkdir_desc
, udf_mkdir
}, /* mkdir */
2358 { &vop_rmdir_desc
, udf_rmdir
}, /* rmdir */
2359 { &vop_symlink_desc
, udf_symlink
}, /* symlink */ /* TODO */
2360 { &vop_readdir_desc
, udf_readdir
}, /* readdir */
2361 { &vop_readlink_desc
, udf_readlink
}, /* readlink */ /* TEST ME */
2362 { &vop_abortop_desc
, genfs_abortop
}, /* abortop */ /* TODO/OK? */
2363 { &vop_inactive_desc
, udf_inactive
}, /* inactive */
2364 { &vop_reclaim_desc
, udf_reclaim
}, /* reclaim */
2365 { &vop_lock_desc
, genfs_lock
}, /* lock */
2366 { &vop_unlock_desc
, genfs_unlock
}, /* unlock */
2367 { &vop_bmap_desc
, udf_trivial_bmap
}, /* bmap */ /* 1:1 bmap */
2368 { &vop_strategy_desc
, udf_vfsstrategy
},/* strategy */
2369 /* { &vop_print_desc, udf_print }, */ /* print */
2370 { &vop_islocked_desc
, genfs_islocked
}, /* islocked */
2371 { &vop_pathconf_desc
, udf_pathconf
}, /* pathconf */
2372 { &vop_advlock_desc
, udf_advlock
}, /* advlock */ /* TEST ME */
2373 { &vop_bwrite_desc
, vn_bwrite
}, /* bwrite */ /* ->strategy */
2374 { &vop_getpages_desc
, genfs_getpages
}, /* getpages */
2375 { &vop_putpages_desc
, genfs_putpages
}, /* putpages */
2380 const struct vnodeopv_desc udf_vnodeop_opv_desc
= {
2381 &udf_vnodeop_p
, udf_vnodeop_entries