1*04076868Sreinoud /* $NetBSD: udf_vnops.c,v 1.127 2023/06/27 09:58:50 reinoud Exp $ */
2cff5e7adSreinoud
3cff5e7adSreinoud /*
4e979c658Sreinoud * Copyright (c) 2006, 2008 Reinoud Zandijk
5cff5e7adSreinoud * All rights reserved.
6cff5e7adSreinoud *
7cff5e7adSreinoud * Redistribution and use in source and binary forms, with or without
8cff5e7adSreinoud * modification, are permitted provided that the following conditions
9cff5e7adSreinoud * are met:
10cff5e7adSreinoud * 1. Redistributions of source code must retain the above copyright
11cff5e7adSreinoud * notice, this list of conditions and the following disclaimer.
12cff5e7adSreinoud * 2. Redistributions in binary form must reproduce the above copyright
13cff5e7adSreinoud * notice, this list of conditions and the following disclaimer in the
14cff5e7adSreinoud * documentation and/or other materials provided with the distribution.
15cff5e7adSreinoud *
16cff5e7adSreinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17cff5e7adSreinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18cff5e7adSreinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19cff5e7adSreinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20cff5e7adSreinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21cff5e7adSreinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22cff5e7adSreinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23cff5e7adSreinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24cff5e7adSreinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25cff5e7adSreinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26cff5e7adSreinoud *
27e979c658Sreinoud * Generic parts are derived from software contributed to The NetBSD Foundation
28e979c658Sreinoud * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
29e979c658Sreinoud * 2005 program.
30e979c658Sreinoud *
31cff5e7adSreinoud */
32cff5e7adSreinoud
33cff5e7adSreinoud #include <sys/cdefs.h>
34cff5e7adSreinoud #ifndef lint
35*04076868Sreinoud __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.127 2023/06/27 09:58:50 reinoud Exp $");
36cff5e7adSreinoud #endif /* not lint */
37cff5e7adSreinoud
38cff5e7adSreinoud
39cff5e7adSreinoud #include <sys/param.h>
40cff5e7adSreinoud #include <sys/systm.h>
41cff5e7adSreinoud #include <sys/namei.h>
42cff5e7adSreinoud #include <sys/resourcevar.h> /* defines plimit structure in proc struct */
43cff5e7adSreinoud #include <sys/kernel.h>
44cff5e7adSreinoud #include <sys/file.h> /* define FWRITE ... */
45cff5e7adSreinoud #include <sys/stat.h>
46cff5e7adSreinoud #include <sys/buf.h>
47cff5e7adSreinoud #include <sys/proc.h>
48cff5e7adSreinoud #include <sys/mount.h>
49cff5e7adSreinoud #include <sys/vnode.h>
50cff5e7adSreinoud #include <sys/signalvar.h>
51cff5e7adSreinoud #include <sys/malloc.h>
52cff5e7adSreinoud #include <sys/dirent.h>
53cff5e7adSreinoud #include <sys/lockf.h>
54e979c658Sreinoud #include <sys/kauth.h>
55cff5e7adSreinoud
56cff5e7adSreinoud #include <miscfs/genfs/genfs.h>
57cff5e7adSreinoud #include <uvm/uvm_extern.h>
58cff5e7adSreinoud
59cff5e7adSreinoud #include <fs/udf/ecma167-udf.h>
60cff5e7adSreinoud #include <fs/udf/udf_mount.h>
61ab09c24fSreinoud #include <sys/dirhash.h>
62ab09c24fSreinoud
63cff5e7adSreinoud #include "udf.h"
64cff5e7adSreinoud #include "udf_subr.h"
65cff5e7adSreinoud #include "udf_bswap.h"
66cff5e7adSreinoud
67cff5e7adSreinoud
68e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) (vnode)->v_data)
69cff5e7adSreinoud
70e3b6b345Sreinoud /* forward declarations */
71e3b6b345Sreinoud static int udf_do_readlink(struct udf_node *udf_node, uint64_t filesize,
72e3b6b345Sreinoud uint8_t *targetbuf, int *length);
73cff5e7adSreinoud
74cff5e7adSreinoud /* implementations of vnode functions; table follows at end */
75cff5e7adSreinoud /* --------------------------------------------------------------------- */
76cff5e7adSreinoud
77cff5e7adSreinoud int
udf_inactive(void * v)78cff5e7adSreinoud udf_inactive(void *v)
79cff5e7adSreinoud {
8087fb3229Sriastradh struct vop_inactive_v2_args /* {
81cff5e7adSreinoud struct vnode *a_vp;
82e979c658Sreinoud bool *a_recycle;
83cff5e7adSreinoud } */ *ap = v;
84cff5e7adSreinoud struct vnode *vp = ap->a_vp;
85e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
86e979c658Sreinoud int refcnt;
87cff5e7adSreinoud
88e979c658Sreinoud DPRINTF(NODE, ("udf_inactive called for udf_node %p\n", VTOI(vp)));
89e979c658Sreinoud
90e979c658Sreinoud if (udf_node == NULL) {
91e979c658Sreinoud DPRINTF(NODE, ("udf_inactive: inactive NULL UDF node\n"));
92e979c658Sreinoud return 0;
93e979c658Sreinoud }
94cff5e7adSreinoud
95cff5e7adSreinoud /*
9694abdca3Shannken * Optionally flush metadata to disc.
97cff5e7adSreinoud */
98e979c658Sreinoud if (udf_node->fe) {
99e979c658Sreinoud refcnt = udf_rw16(udf_node->fe->link_cnt);
100e979c658Sreinoud } else {
101e979c658Sreinoud assert(udf_node->efe);
102e979c658Sreinoud refcnt = udf_rw16(udf_node->efe->link_cnt);
103e979c658Sreinoud }
104e979c658Sreinoud
1051f6bbe27Sreinoud if ((refcnt == 0) && (vp->v_vflag & VV_SYSTEM)) {
106e979c658Sreinoud DPRINTF(VOLUMES, ("UDF_INACTIVE deleting VV_SYSTEM\n"));
1077f459241Sandvar /* system nodes are not written out on inactive, so flush */
1081f6bbe27Sreinoud udf_node->i_flags = 0;
1091f6bbe27Sreinoud }
110e979c658Sreinoud
111e979c658Sreinoud *ap->a_recycle = false;
112e979c658Sreinoud if ((refcnt == 0) && ((vp->v_vflag & VV_SYSTEM) == 0)) {
113e979c658Sreinoud *ap->a_recycle = true;
114e979c658Sreinoud return 0;
115e979c658Sreinoud }
116e979c658Sreinoud
117e979c658Sreinoud /* write out its node */
118e979c658Sreinoud if (udf_node->i_flags & (IN_CHANGE | IN_UPDATE | IN_MODIFIED))
1199d15fe51Sreinoud udf_update(vp, NULL, NULL, NULL, 0);
120cff5e7adSreinoud
121cff5e7adSreinoud return 0;
122cff5e7adSreinoud }
123cff5e7adSreinoud
124cff5e7adSreinoud /* --------------------------------------------------------------------- */
125cff5e7adSreinoud
126cff5e7adSreinoud int
udf_reclaim(void * v)127cff5e7adSreinoud udf_reclaim(void *v)
128cff5e7adSreinoud {
1297f7aad09Sriastradh struct vop_reclaim_v2_args /* {
130cff5e7adSreinoud struct vnode *a_vp;
131cff5e7adSreinoud } */ *ap = v;
132cff5e7adSreinoud struct vnode *vp = ap->a_vp;
133e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
13494abdca3Shannken int refcnt;
135cff5e7adSreinoud
1367f7aad09Sriastradh VOP_UNLOCK(vp);
1377f7aad09Sriastradh
138e979c658Sreinoud DPRINTF(NODE, ("udf_reclaim called for node %p\n", udf_node));
139cff5e7adSreinoud
140e979c658Sreinoud if (udf_node == NULL) {
141e979c658Sreinoud DPRINTF(NODE, ("udf_reclaim(): null udfnode\n"));
142e979c658Sreinoud return 0;
143e979c658Sreinoud }
144e979c658Sreinoud
14594abdca3Shannken /*
14694abdca3Shannken * If the file has not been referenced anymore in a directory
14794abdca3Shannken * we ought to free up the resources on disc if applicable.
14894abdca3Shannken */
14994abdca3Shannken if (udf_node->fe) {
15094abdca3Shannken refcnt = udf_rw16(udf_node->fe->link_cnt);
15194abdca3Shannken } else {
15294abdca3Shannken assert(udf_node->efe);
15394abdca3Shannken refcnt = udf_rw16(udf_node->efe->link_cnt);
15494abdca3Shannken }
15594abdca3Shannken
15694abdca3Shannken if ((refcnt == 0) && ((vp->v_vflag & VV_SYSTEM) == 0)) {
15794abdca3Shannken /* remove this file's allocation */
15894abdca3Shannken DPRINTF(NODE, ("udf_inactive deleting unlinked file\n"));
15994abdca3Shannken udf_delete_node(udf_node);
16094abdca3Shannken }
16194abdca3Shannken
162e979c658Sreinoud /* update note for closure */
1639d15fe51Sreinoud udf_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
164e979c658Sreinoud
165e979c658Sreinoud /* async check to see if all node descriptors are written out */
166*04076868Sreinoud mutex_enter(&udf_node->node_mutex);
167e979c658Sreinoud while ((volatile int) udf_node->outstanding_nodedscr > 0) {
168e979c658Sreinoud vprint("udf_reclaim(): waiting for writeout\n", vp);
169*04076868Sreinoud cv_timedwait(&udf_node->node_lock, &udf_node->node_mutex, hz/8);
170e979c658Sreinoud }
171*04076868Sreinoud mutex_exit(&udf_node->node_mutex);
172e979c658Sreinoud
173cff5e7adSreinoud /* dispose all node knowledge */
174e979c658Sreinoud udf_dispose_node(udf_node);
175cff5e7adSreinoud
176cff5e7adSreinoud return 0;
177cff5e7adSreinoud }
178cff5e7adSreinoud
179cff5e7adSreinoud /* --------------------------------------------------------------------- */
180cff5e7adSreinoud
181cff5e7adSreinoud int
udf_read(void * v)182cff5e7adSreinoud udf_read(void *v)
183cff5e7adSreinoud {
184cff5e7adSreinoud struct vop_read_args /* {
185cff5e7adSreinoud struct vnode *a_vp;
186cff5e7adSreinoud struct uio *a_uio;
187cff5e7adSreinoud int a_ioflag;
188fc9422c9Selad kauth_cred_t a_cred;
189cff5e7adSreinoud } */ *ap = v;
190cff5e7adSreinoud struct vnode *vp = ap->a_vp;
191cff5e7adSreinoud struct uio *uio = ap->a_uio;
192cff5e7adSreinoud int ioflag = ap->a_ioflag;
193e979c658Sreinoud int advice = IO_ADV_DECODE(ap->a_ioflag);
194cff5e7adSreinoud struct uvm_object *uobj;
195cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
196cff5e7adSreinoud struct file_entry *fe;
197cff5e7adSreinoud struct extfile_entry *efe;
198cff5e7adSreinoud uint64_t file_size;
199cff5e7adSreinoud vsize_t len;
200cff5e7adSreinoud int error;
201cff5e7adSreinoud
202e979c658Sreinoud /*
203e979c658Sreinoud * XXX reading from extended attributes not yet implemented. FreeBSD
204e979c658Sreinoud * has it in mind to forward the IO_EXT read call to the
205e979c658Sreinoud * VOP_READEXTATTR().
206e979c658Sreinoud */
207cff5e7adSreinoud
208cff5e7adSreinoud DPRINTF(READ, ("udf_read called\n"));
209cff5e7adSreinoud
210cff5e7adSreinoud /* can this happen? some filingsystems have this check */
211cff5e7adSreinoud if (uio->uio_offset < 0)
212cff5e7adSreinoud return EINVAL;
213e979c658Sreinoud if (uio->uio_resid == 0)
214e979c658Sreinoud return 0;
215e979c658Sreinoud
216e979c658Sreinoud /* protect against rogue programs reading raw directories and links */
217e979c658Sreinoud if ((ioflag & IO_ALTSEMANTICS) == 0) {
218e979c658Sreinoud if (vp->v_type == VDIR)
219e979c658Sreinoud return EISDIR;
220e979c658Sreinoud /* all but regular files just give EINVAL */
221e979c658Sreinoud if (vp->v_type != VREG)
222e979c658Sreinoud return EINVAL;
223e979c658Sreinoud }
224cff5e7adSreinoud
225cff5e7adSreinoud assert(udf_node);
226cff5e7adSreinoud assert(udf_node->fe || udf_node->efe);
227cff5e7adSreinoud
228e979c658Sreinoud /* get file/directory filesize */
229cff5e7adSreinoud if (udf_node->fe) {
230cff5e7adSreinoud fe = udf_node->fe;
231cff5e7adSreinoud file_size = udf_rw64(fe->inf_len);
232cff5e7adSreinoud } else {
233cff5e7adSreinoud assert(udf_node->efe);
234cff5e7adSreinoud efe = udf_node->efe;
235cff5e7adSreinoud file_size = udf_rw64(efe->inf_len);
2360c1391f0Schristos }
237cff5e7adSreinoud
238cff5e7adSreinoud /* read contents using buffercache */
239cff5e7adSreinoud uobj = &vp->v_uobj;
240cff5e7adSreinoud error = 0;
241cff5e7adSreinoud while (uio->uio_resid > 0) {
242cff5e7adSreinoud /* reached end? */
243cff5e7adSreinoud if (file_size <= uio->uio_offset)
244cff5e7adSreinoud break;
245cff5e7adSreinoud
246cff5e7adSreinoud /* maximise length to file extremity */
247cff5e7adSreinoud len = MIN(file_size - uio->uio_offset, uio->uio_resid);
248cff5e7adSreinoud if (len == 0)
249cff5e7adSreinoud break;
250cff5e7adSreinoud
251cff5e7adSreinoud /* ubc, here we come, prepare to trap */
252b4099c3eSpooka error = ubc_uiomove(uobj, uio, len, advice,
253f5ad84fdSad UBC_READ | UBC_PARTIALOK | UBC_VNODE_FLAGS(vp));
254cff5e7adSreinoud if (error)
255cff5e7adSreinoud break;
256cff5e7adSreinoud }
257e979c658Sreinoud
258e979c658Sreinoud /* note access time unless not requested */
259e979c658Sreinoud if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
260e979c658Sreinoud udf_node->i_flags |= IN_ACCESS;
261a26f29c6Sriastradh if ((ioflag & IO_SYNC) == IO_SYNC) {
262a26f29c6Sriastradh int uerror;
263a26f29c6Sriastradh
264a26f29c6Sriastradh uerror = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT);
265a26f29c6Sriastradh if (error == 0)
266a26f29c6Sriastradh error = uerror;
267a26f29c6Sriastradh }
2680c1391f0Schristos }
269cff5e7adSreinoud
270e979c658Sreinoud return error;
271cff5e7adSreinoud }
272cff5e7adSreinoud
273cff5e7adSreinoud /* --------------------------------------------------------------------- */
274cff5e7adSreinoud
275cff5e7adSreinoud int
udf_write(void * v)276cff5e7adSreinoud udf_write(void *v)
277cff5e7adSreinoud {
278cff5e7adSreinoud struct vop_write_args /* {
279cff5e7adSreinoud struct vnode *a_vp;
280cff5e7adSreinoud struct uio *a_uio;
281cff5e7adSreinoud int a_ioflag;
282fc9422c9Selad kauth_cred_t a_cred;
283cff5e7adSreinoud } */ *ap = v;
284e979c658Sreinoud struct vnode *vp = ap->a_vp;
285e979c658Sreinoud struct uio *uio = ap->a_uio;
286e979c658Sreinoud int ioflag = ap->a_ioflag;
287c76ee532Sreinoud kauth_cred_t cred = ap->a_cred;
288e979c658Sreinoud int advice = IO_ADV_DECODE(ap->a_ioflag);
289e979c658Sreinoud struct uvm_object *uobj;
290e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
291e979c658Sreinoud struct file_entry *fe;
292e979c658Sreinoud struct extfile_entry *efe;
29378466aa1Sreinoud uint64_t file_size, old_size, old_offset;
294e979c658Sreinoud vsize_t len;
295706de0e5Sreinoud int aflag = ioflag & IO_SYNC ? B_SYNC : 0;
296e979c658Sreinoud int error;
297b4099c3eSpooka int resid, extended;
298cff5e7adSreinoud
299e979c658Sreinoud /*
300e979c658Sreinoud * XXX writing to extended attributes not yet implemented. FreeBSD has
301e979c658Sreinoud * it in mind to forward the IO_EXT read call to the
302e979c658Sreinoud * VOP_READEXTATTR().
303e979c658Sreinoud */
304cff5e7adSreinoud
305e979c658Sreinoud DPRINTF(WRITE, ("udf_write called\n"));
306e979c658Sreinoud
307e979c658Sreinoud /* can this happen? some filingsystems have this check */
308e979c658Sreinoud if (uio->uio_offset < 0)
309e979c658Sreinoud return EINVAL;
310e979c658Sreinoud if (uio->uio_resid == 0)
311e979c658Sreinoud return 0;
312e979c658Sreinoud
313e979c658Sreinoud /* protect against rogue programs writing raw directories or links */
314e979c658Sreinoud if ((ioflag & IO_ALTSEMANTICS) == 0) {
315e979c658Sreinoud if (vp->v_type == VDIR)
316e979c658Sreinoud return EISDIR;
317e979c658Sreinoud /* all but regular files just give EINVAL for now */
318e979c658Sreinoud if (vp->v_type != VREG)
319e979c658Sreinoud return EINVAL;
320e979c658Sreinoud }
321e979c658Sreinoud
322e979c658Sreinoud assert(udf_node);
323e979c658Sreinoud assert(udf_node->fe || udf_node->efe);
324e979c658Sreinoud
325e979c658Sreinoud /* get file/directory filesize */
326e979c658Sreinoud if (udf_node->fe) {
327e979c658Sreinoud fe = udf_node->fe;
328e979c658Sreinoud file_size = udf_rw64(fe->inf_len);
329e979c658Sreinoud } else {
330e979c658Sreinoud assert(udf_node->efe);
331e979c658Sreinoud efe = udf_node->efe;
332e979c658Sreinoud file_size = udf_rw64(efe->inf_len);
333e979c658Sreinoud }
334e979c658Sreinoud old_size = file_size;
335e979c658Sreinoud
336e979c658Sreinoud /* if explicitly asked to append, uio_offset can be wrong? */
337e979c658Sreinoud if (ioflag & IO_APPEND)
338e979c658Sreinoud uio->uio_offset = file_size;
339e979c658Sreinoud
340e979c658Sreinoud extended = (uio->uio_offset + uio->uio_resid > file_size);
341e979c658Sreinoud if (extended) {
342e979c658Sreinoud DPRINTF(WRITE, ("extending file from %"PRIu64" to %"PRIu64"\n",
343e979c658Sreinoud file_size, uio->uio_offset + uio->uio_resid));
344e979c658Sreinoud error = udf_grow_node(udf_node, uio->uio_offset + uio->uio_resid);
345e979c658Sreinoud if (error)
346e979c658Sreinoud return error;
347e979c658Sreinoud file_size = uio->uio_offset + uio->uio_resid;
348e979c658Sreinoud }
349e979c658Sreinoud
350e979c658Sreinoud /* write contents using buffercache */
351e979c658Sreinoud uobj = &vp->v_uobj;
352e979c658Sreinoud resid = uio->uio_resid;
353e979c658Sreinoud error = 0;
354e979c658Sreinoud
355e979c658Sreinoud uvm_vnp_setwritesize(vp, file_size);
356193ccd2dSreinoud old_offset = uio->uio_offset;
357e979c658Sreinoud while (uio->uio_resid > 0) {
358e979c658Sreinoud /* maximise length to file extremity */
359e979c658Sreinoud len = MIN(file_size - uio->uio_offset, uio->uio_resid);
360e979c658Sreinoud if (len == 0)
361e979c658Sreinoud break;
362e979c658Sreinoud
363706de0e5Sreinoud genfs_node_wrlock(vp);
364706de0e5Sreinoud error = GOP_ALLOC(vp, uio->uio_offset, len, aflag, cred);
365706de0e5Sreinoud genfs_node_unlock(vp);
366706de0e5Sreinoud if (error)
367706de0e5Sreinoud break;
368706de0e5Sreinoud
369e979c658Sreinoud /* ubc, here we come, prepare to trap */
370b4099c3eSpooka error = ubc_uiomove(uobj, uio, len, advice,
371f5ad84fdSad UBC_WRITE | UBC_VNODE_FLAGS(vp));
372e979c658Sreinoud if (error)
373e979c658Sreinoud break;
37478466aa1Sreinoud
37578466aa1Sreinoud /*
37678466aa1Sreinoud * flush what we just wrote if necessary.
37778466aa1Sreinoud * XXXUBC simplistic async flushing.
378193ccd2dSreinoud *
379c1a508d1Sreinoud * Directories are excluded since its file data that we want
380c1a508d1Sreinoud * to purge.
38178466aa1Sreinoud */
382793c315aSreinoud if ((vp->v_type != VDIR) &&
383c1a508d1Sreinoud (old_offset >> 16 != uio->uio_offset >> 16)) {
384d2a0ebb6Sad rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
385c1a508d1Sreinoud error = VOP_PUTPAGES(vp, (old_offset >> 16) << 16,
3868306a9edSchs (uio->uio_offset >> 16) << 16,
3878306a9edSchs PGO_CLEANIT | PGO_LAZY);
388193ccd2dSreinoud old_offset = uio->uio_offset;
38978466aa1Sreinoud }
390e979c658Sreinoud }
391e979c658Sreinoud uvm_vnp_setsize(vp, file_size);
392e979c658Sreinoud
393e979c658Sreinoud /* mark node changed and request update */
394e979c658Sreinoud udf_node->i_flags |= IN_CHANGE | IN_UPDATE;
395d11ea3eaSchristos if (vp->v_mount->mnt_flag & MNT_RELATIME)
396d11ea3eaSchristos udf_node->i_flags |= IN_ACCESS;
397e979c658Sreinoud
398e979c658Sreinoud /*
399e979c658Sreinoud * XXX TODO FFS has code here to reset setuid & setgid when we're not
400e979c658Sreinoud * the superuser as a precaution against tampering.
401e979c658Sreinoud */
402e979c658Sreinoud
403e979c658Sreinoud if (error) {
404e979c658Sreinoud /* bring back file size to its former size */
405e979c658Sreinoud /* take notice of its errors? */
4068f6cc2bdSreinoud (void) udf_chsize(vp, (u_quad_t) old_size, cred);
407e979c658Sreinoud
408e979c658Sreinoud /* roll back uio */
409e979c658Sreinoud uio->uio_offset -= resid - uio->uio_resid;
410e979c658Sreinoud uio->uio_resid = resid;
411e979c658Sreinoud } else {
412e979c658Sreinoud /* if we write and we're synchronous, update node */
413e979c658Sreinoud if ((resid > uio->uio_resid) && ((ioflag & IO_SYNC) == IO_SYNC))
4149d15fe51Sreinoud error = udf_update(vp, NULL, NULL, NULL, UPDATE_WAIT);
415e979c658Sreinoud }
416e979c658Sreinoud
417e979c658Sreinoud return error;
418cff5e7adSreinoud }
419cff5e7adSreinoud
420cff5e7adSreinoud
421cff5e7adSreinoud /* --------------------------------------------------------------------- */
422cff5e7adSreinoud
423cff5e7adSreinoud /*
42409fb1792Sandvar * `Special' bmap functionality that translates all incoming requests to
425cff5e7adSreinoud * translate to vop_strategy() calls with the same blocknumbers effectively
426cff5e7adSreinoud * not translating at all.
427cff5e7adSreinoud */
428cff5e7adSreinoud
429cff5e7adSreinoud int
udf_trivial_bmap(void * v)430cff5e7adSreinoud udf_trivial_bmap(void *v)
431cff5e7adSreinoud {
432cff5e7adSreinoud struct vop_bmap_args /* {
433cff5e7adSreinoud struct vnode *a_vp;
434cff5e7adSreinoud daddr_t a_bn;
435cff5e7adSreinoud struct vnode **a_vpp;
436cff5e7adSreinoud daddr_t *a_bnp;
437cff5e7adSreinoud int *a_runp;
438cff5e7adSreinoud } */ *ap = v;
439cff5e7adSreinoud struct vnode *vp = ap->a_vp; /* our node */
440cff5e7adSreinoud struct vnode **vpp = ap->a_vpp; /* return node */
441cff5e7adSreinoud daddr_t *bnp = ap->a_bnp; /* translated */
44209fb1792Sandvar daddr_t bn = ap->a_bn; /* original */
443cff5e7adSreinoud int *runp = ap->a_runp;
444cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
445cff5e7adSreinoud uint32_t lb_size;
446cff5e7adSreinoud
447cff5e7adSreinoud /* get logical block size */
448cff5e7adSreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
449cff5e7adSreinoud
450cff5e7adSreinoud /* could return `-1' to indicate holes/zeros */
451cff5e7adSreinoud /* translate 1:1 */
452cff5e7adSreinoud *bnp = bn;
453cff5e7adSreinoud
454cff5e7adSreinoud /* set the vnode to read the data from with strategy on itself */
455cff5e7adSreinoud if (vpp)
456cff5e7adSreinoud *vpp = vp;
457cff5e7adSreinoud
458cff5e7adSreinoud /* set runlength of maximum block size */
459cff5e7adSreinoud if (runp)
460cff5e7adSreinoud *runp = MAXPHYS / lb_size; /* or with -1 ? */
461cff5e7adSreinoud
462cff5e7adSreinoud /* return success */
463cff5e7adSreinoud return 0;
464cff5e7adSreinoud }
465cff5e7adSreinoud
466cff5e7adSreinoud /* --------------------------------------------------------------------- */
467cff5e7adSreinoud
468cff5e7adSreinoud int
udf_vfsstrategy(void * v)469e979c658Sreinoud udf_vfsstrategy(void *v)
470cff5e7adSreinoud {
471cff5e7adSreinoud struct vop_strategy_args /* {
472cff5e7adSreinoud struct vnode *a_vp;
473cff5e7adSreinoud struct buf *a_bp;
474cff5e7adSreinoud } */ *ap = v;
475cff5e7adSreinoud struct vnode *vp = ap->a_vp;
476cff5e7adSreinoud struct buf *bp = ap->a_bp;
477cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
47891b2f42cSchristos uint32_t lb_size, sectors;
479cff5e7adSreinoud
480cff5e7adSreinoud DPRINTF(STRATEGY, ("udf_strategy called\n"));
481cff5e7adSreinoud
482cff5e7adSreinoud /* check if we ought to be here */
483cff5e7adSreinoud if (vp->v_type == VBLK || vp->v_type == VCHR)
484cff5e7adSreinoud panic("udf_strategy: spec");
485cff5e7adSreinoud
486e979c658Sreinoud /* only filebuffers ought to be read/write by this, no descriptors */
487cff5e7adSreinoud assert(bp->b_blkno >= 0);
488cff5e7adSreinoud
489cff5e7adSreinoud /* get sector size */
490cff5e7adSreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
491cff5e7adSreinoud
492cff5e7adSreinoud /* calculate length to fetch/store in sectors */
493cff5e7adSreinoud sectors = bp->b_bcount / lb_size;
494cff5e7adSreinoud assert(bp->b_bcount > 0);
495cff5e7adSreinoud
496d97db384Ssnj /* NEVER assume later that this buffer is already translated */
497cff5e7adSreinoud /* bp->b_lblkno = bp->b_blkno; */
498cff5e7adSreinoud
499e979c658Sreinoud /* check assertions: we OUGHT to always get multiples of this */
500e979c658Sreinoud assert(sectors * lb_size == bp->b_bcount);
5010f18888bSchristos __USE(sectors);
502e979c658Sreinoud
503e979c658Sreinoud /* issue buffer */
504e979c658Sreinoud if (bp->b_flags & B_READ) {
505cff5e7adSreinoud DPRINTF(STRATEGY, ("\tread vp %p buf %p (blk no %"PRIu64")"
50691b2f42cSchristos ", for %d sectors\n",
50791b2f42cSchristos vp, bp, bp->b_blkno, sectors));
508cff5e7adSreinoud
509cff5e7adSreinoud /* read buffer from the udf_node, translate vtop on the way*/
510cff5e7adSreinoud udf_read_filebuf(udf_node, bp);
511e979c658Sreinoud } else {
512e979c658Sreinoud DPRINTF(STRATEGY, ("\twrite vp %p buf %p (blk no %"PRIu64")"
51391b2f42cSchristos ", for %d sectors\n",
51491b2f42cSchristos vp, bp, bp->b_blkno, sectors));
515e979c658Sreinoud
516e979c658Sreinoud /* write buffer to the udf_node, translate vtop on the way*/
517e979c658Sreinoud udf_write_filebuf(udf_node, bp);
5180c1391f0Schristos }
519cff5e7adSreinoud
520e979c658Sreinoud return bp->b_error;
521cff5e7adSreinoud }
522cff5e7adSreinoud
523cff5e7adSreinoud /* --------------------------------------------------------------------- */
524cff5e7adSreinoud
525cff5e7adSreinoud int
udf_readdir(void * v)526cff5e7adSreinoud udf_readdir(void *v)
527cff5e7adSreinoud {
528cff5e7adSreinoud struct vop_readdir_args /* {
529cff5e7adSreinoud struct vnode *a_vp;
530cff5e7adSreinoud struct uio *a_uio;
531fc9422c9Selad kauth_cred_t a_cred;
532cff5e7adSreinoud int *a_eofflag;
533cff5e7adSreinoud off_t **a_cookies;
534cff5e7adSreinoud int *a_ncookies;
535cff5e7adSreinoud } */ *ap = v;
536cff5e7adSreinoud struct uio *uio = ap->a_uio;
537cff5e7adSreinoud struct vnode *vp = ap->a_vp;
538cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
539cff5e7adSreinoud struct file_entry *fe;
540cff5e7adSreinoud struct extfile_entry *efe;
541cff5e7adSreinoud struct fileid_desc *fid;
5420ae0a486Srumble struct dirent *dirent;
543cff5e7adSreinoud uint64_t file_size, diroffset, transoffset;
544cff5e7adSreinoud uint32_t lb_size;
545cff5e7adSreinoud int error;
546cff5e7adSreinoud
547cff5e7adSreinoud DPRINTF(READDIR, ("udf_readdir called\n"));
548cff5e7adSreinoud
549cff5e7adSreinoud /* This operation only makes sense on directory nodes. */
550cff5e7adSreinoud if (vp->v_type != VDIR)
551cff5e7adSreinoud return ENOTDIR;
552cff5e7adSreinoud
553cff5e7adSreinoud /* get directory filesize */
554cff5e7adSreinoud if (udf_node->fe) {
555cff5e7adSreinoud fe = udf_node->fe;
556cff5e7adSreinoud file_size = udf_rw64(fe->inf_len);
557cff5e7adSreinoud } else {
558cff5e7adSreinoud assert(udf_node->efe);
559cff5e7adSreinoud efe = udf_node->efe;
560cff5e7adSreinoud file_size = udf_rw64(efe->inf_len);
5610c1391f0Schristos }
562cff5e7adSreinoud
5630ae0a486Srumble dirent = malloc(sizeof(struct dirent), M_UDFTEMP, M_WAITOK | M_ZERO);
5640ae0a486Srumble
565cff5e7adSreinoud /*
566cff5e7adSreinoud * Add `.' pseudo entry if at offset zero since its not in the fid
567cff5e7adSreinoud * stream
568cff5e7adSreinoud */
569cff5e7adSreinoud if (uio->uio_offset == 0) {
570cff5e7adSreinoud DPRINTF(READDIR, ("\t'.' inserted\n"));
5710ae0a486Srumble strcpy(dirent->d_name, ".");
572c093c252Sreinoud dirent->d_fileno = udf_get_node_id(&udf_node->loc);
5730ae0a486Srumble dirent->d_type = DT_DIR;
5740ae0a486Srumble dirent->d_namlen = strlen(dirent->d_name);
5750ae0a486Srumble dirent->d_reclen = _DIRENT_SIZE(dirent);
5760ae0a486Srumble uiomove(dirent, _DIRENT_SIZE(dirent), uio);
577cff5e7adSreinoud
578cff5e7adSreinoud /* mark with magic value that we have done the dummy */
579cff5e7adSreinoud uio->uio_offset = UDF_DIRCOOKIE_DOT;
5800c1391f0Schristos }
581cff5e7adSreinoud
582cff5e7adSreinoud /* we are called just as long as we keep on pushing data in */
583cff5e7adSreinoud error = 0;
5840be5b3feSreinoud if (uio->uio_offset < file_size) {
585cff5e7adSreinoud /* allocate temporary space for fid */
586cff5e7adSreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size);
5870ae0a486Srumble fid = malloc(lb_size, M_UDFTEMP, M_WAITOK);
588cff5e7adSreinoud
589cff5e7adSreinoud if (uio->uio_offset == UDF_DIRCOOKIE_DOT)
590cff5e7adSreinoud uio->uio_offset = 0;
591cff5e7adSreinoud
592cff5e7adSreinoud diroffset = uio->uio_offset;
593cff5e7adSreinoud transoffset = diroffset;
594cff5e7adSreinoud while (diroffset < file_size) {
595cff5e7adSreinoud DPRINTF(READDIR, ("\tread in fid stream\n"));
596cff5e7adSreinoud /* transfer a new fid/dirent */
5972f9a24b6Sreinoud error = udf_read_fid_stream(vp, &diroffset, fid, dirent);
598cff5e7adSreinoud DPRINTFIF(READDIR, error, ("read error in read fid "
599cff5e7adSreinoud "stream : %d\n", error));
600cff5e7adSreinoud if (error)
601cff5e7adSreinoud break;
602cff5e7adSreinoud
603cff5e7adSreinoud /*
604cff5e7adSreinoud * If there isn't enough space in the uio to return a
605cff5e7adSreinoud * whole dirent, break off read
606cff5e7adSreinoud */
6070ae0a486Srumble if (uio->uio_resid < _DIRENT_SIZE(dirent))
608cff5e7adSreinoud break;
609cff5e7adSreinoud
610a0403cdeSmsaitoh /* remember the last entry we transferred */
611cff5e7adSreinoud transoffset = diroffset;
612cff5e7adSreinoud
613cff5e7adSreinoud /* skip deleted entries */
614cff5e7adSreinoud if (fid->file_char & UDF_FILE_CHAR_DEL)
615cff5e7adSreinoud continue;
616cff5e7adSreinoud
617cff5e7adSreinoud /* skip not visible files */
618cff5e7adSreinoud if (fid->file_char & UDF_FILE_CHAR_VIS)
619cff5e7adSreinoud continue;
620cff5e7adSreinoud
621cff5e7adSreinoud /* copy dirent to the caller */
622cff5e7adSreinoud DPRINTF(READDIR, ("\tread dirent `%s', type %d\n",
6230ae0a486Srumble dirent->d_name, dirent->d_type));
6240ae0a486Srumble uiomove(dirent, _DIRENT_SIZE(dirent), uio);
6250c1391f0Schristos }
626cff5e7adSreinoud
6277991f5a7Sandvar /* pass on last transferred offset */
628cff5e7adSreinoud uio->uio_offset = transoffset;
6290ae0a486Srumble free(fid, M_UDFTEMP);
6300c1391f0Schristos }
631cff5e7adSreinoud
632cff5e7adSreinoud if (ap->a_eofflag)
6330be5b3feSreinoud *ap->a_eofflag = (uio->uio_offset >= file_size);
634cff5e7adSreinoud
635cff5e7adSreinoud #ifdef DEBUG
636cff5e7adSreinoud if (udf_verbose & UDF_DEBUG_READDIR) {
637cff5e7adSreinoud printf("returning offset %d\n", (uint32_t) uio->uio_offset);
638cff5e7adSreinoud if (ap->a_eofflag)
639cff5e7adSreinoud printf("returning EOF ? %d\n", *ap->a_eofflag);
640cff5e7adSreinoud if (error)
641cff5e7adSreinoud printf("readdir returning error %d\n", error);
6420c1391f0Schristos }
643cff5e7adSreinoud #endif
644cff5e7adSreinoud
6450ae0a486Srumble free(dirent, M_UDFTEMP);
646cff5e7adSreinoud return error;
647cff5e7adSreinoud }
648cff5e7adSreinoud
649cff5e7adSreinoud /* --------------------------------------------------------------------- */
650cff5e7adSreinoud
651cff5e7adSreinoud int
udf_lookup(void * v)652cff5e7adSreinoud udf_lookup(void *v)
653cff5e7adSreinoud {
65497834f7bShannken struct vop_lookup_v2_args /* {
655cff5e7adSreinoud struct vnode *a_dvp;
656cff5e7adSreinoud struct vnode **a_vpp;
657cff5e7adSreinoud struct componentname *a_cnp;
658cff5e7adSreinoud } */ *ap = v;
659cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
660cff5e7adSreinoud struct vnode **vpp = ap->a_vpp;
661cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
662cff5e7adSreinoud struct udf_node *dir_node, *res_node;
663cff5e7adSreinoud struct udf_mount *ump;
664cff5e7adSreinoud struct long_ad icb_loc;
66516cc237eSreinoud mode_t mode;
66616cc237eSreinoud uid_t d_uid;
66716cc237eSreinoud gid_t d_gid;
668cff5e7adSreinoud const char *name;
669c398ae97Schs int namelen, nameiop, islastcn, mounted_ro;
670cff5e7adSreinoud int error, found;
671cff5e7adSreinoud
672cff5e7adSreinoud dir_node = VTOI(dvp);
673cff5e7adSreinoud ump = dir_node->ump;
674cff5e7adSreinoud *vpp = NULL;
675cff5e7adSreinoud
676a7795a09Sreinoud DPRINTF(LOOKUP, ("udf_lookup called, lookup `%s`\n",
677a7795a09Sreinoud cnp->cn_nameptr));
678cff5e7adSreinoud
679cff5e7adSreinoud /* simplify/clarification flags */
680cff5e7adSreinoud nameiop = cnp->cn_nameiop;
681cff5e7adSreinoud islastcn = cnp->cn_flags & ISLASTCN;
682cff5e7adSreinoud mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY;
683cff5e7adSreinoud
684cff5e7adSreinoud /* check exec/dirread permissions first */
68561e8303eSpooka error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
686cff5e7adSreinoud if (error)
687cff5e7adSreinoud return error;
688cff5e7adSreinoud
689cff5e7adSreinoud DPRINTF(LOOKUP, ("\taccess ok\n"));
690cff5e7adSreinoud
691cff5e7adSreinoud /*
692cff5e7adSreinoud * If requesting a modify on the last path element on a read-only
693cff5e7adSreinoud * filingsystem, reject lookup; XXX why is this repeated in every FS ?
694cff5e7adSreinoud */
695cff5e7adSreinoud if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME))
696cff5e7adSreinoud return EROFS;
697cff5e7adSreinoud
698cff5e7adSreinoud DPRINTF(LOOKUP, ("\tlooking up cnp->cn_nameptr '%s'\n",
699cff5e7adSreinoud cnp->cn_nameptr));
7001617a81dSdholland /* look in the namecache */
70135ed6905Sdholland if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
70235ed6905Sdholland cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
7031617a81dSdholland return *vpp == NULLVP ? ENOENT : 0;
7041617a81dSdholland }
705cff5e7adSreinoud
706cff5e7adSreinoud DPRINTF(LOOKUP, ("\tNOT found in cache\n"));
707cff5e7adSreinoud
708cff5e7adSreinoud /*
709cff5e7adSreinoud * Obviously, the file is not (anymore) in the namecache, we have to
710cff5e7adSreinoud * search for it. There are three basic cases: '.', '..' and others.
711cff5e7adSreinoud *
712cff5e7adSreinoud * Following the guidelines of VOP_LOOKUP manpage and tmpfs.
713cff5e7adSreinoud */
714cff5e7adSreinoud error = 0;
715cff5e7adSreinoud if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) {
716cff5e7adSreinoud DPRINTF(LOOKUP, ("\tlookup '.'\n"));
717cff5e7adSreinoud /* special case 1 '.' */
71816cc237eSreinoud if (islastcn && cnp->cn_nameiop == RENAME) {
71916cc237eSreinoud error = EISDIR;
72016cc237eSreinoud goto out;
72116cc237eSreinoud }
722c3183f32Spooka vref(dvp);
723cff5e7adSreinoud *vpp = dvp;
724cff5e7adSreinoud /* done */
72516cc237eSreinoud goto done;
726cff5e7adSreinoud } else if (cnp->cn_flags & ISDOTDOT) {
727cff5e7adSreinoud /* special case 2 '..' */
728cff5e7adSreinoud DPRINTF(LOOKUP, ("\tlookup '..'\n"));
729cff5e7adSreinoud
730a7795a09Sreinoud if (islastcn && cnp->cn_nameiop == RENAME) {
731a7795a09Sreinoud error = EINVAL;
732a7795a09Sreinoud goto out;
733a7795a09Sreinoud }
734a7795a09Sreinoud
735cff5e7adSreinoud /* get our node */
736cff5e7adSreinoud name = "..";
737cff5e7adSreinoud namelen = 2;
7382ac28d55Sreinoud error = udf_lookup_name_in_dir(dvp, name, namelen,
7392ac28d55Sreinoud &icb_loc, &found);
7402ac28d55Sreinoud if (error)
7412ac28d55Sreinoud goto out;
742cff5e7adSreinoud if (!found)
743cff5e7adSreinoud error = ENOENT;
744cff5e7adSreinoud
745e4424d53Sreinoud /* first unlock parent */
7461423e65bShannken VOP_UNLOCK(dvp);
747e4424d53Sreinoud
748e979c658Sreinoud if (error == 0) {
749cff5e7adSreinoud DPRINTF(LOOKUP, ("\tfound '..'\n"));
750cff5e7adSreinoud /* try to create/reuse the node */
751c2e9cb94Sad error = udf_get_node(ump, &icb_loc, &res_node,
752c2e9cb94Sad LK_EXCLUSIVE);
753cff5e7adSreinoud
754cff5e7adSreinoud if (!error) {
7552ac28d55Sreinoud DPRINTF(LOOKUP,
7562ac28d55Sreinoud ("\tnode retrieved/created OK\n"));
757cff5e7adSreinoud *vpp = res_node->vnode;
7580c1391f0Schristos }
7590c1391f0Schristos }
760cff5e7adSreinoud
761c398ae97Schs /* try to relock parent */
762c398ae97Schs vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
76316cc237eSreinoud goto out;
76416cc237eSreinoud }
76516cc237eSreinoud
766cff5e7adSreinoud /* all other files */
76716cc237eSreinoud DPRINTF(LOOKUP, ("\tlookup file/dir in directory\n"));
76816cc237eSreinoud
769cff5e7adSreinoud /* lookup filename in the directory; location icb_loc */
770cff5e7adSreinoud name = cnp->cn_nameptr;
771cff5e7adSreinoud namelen = cnp->cn_namelen;
7722ac28d55Sreinoud error = udf_lookup_name_in_dir(dvp, name, namelen,
7732ac28d55Sreinoud &icb_loc, &found);
7742ac28d55Sreinoud if (error)
7752ac28d55Sreinoud goto out;
776cff5e7adSreinoud if (!found) {
777cff5e7adSreinoud DPRINTF(LOOKUP, ("\tNOT found\n"));
778cff5e7adSreinoud /*
77916cc237eSreinoud * The entry was not found in the directory. This is
78016cc237eSreinoud * valid if we are creating or renaming an entry and
78116cc237eSreinoud * are working on the last component of the path name.
782cff5e7adSreinoud */
78316cc237eSreinoud if (islastcn && (cnp->cn_nameiop == CREATE ||
78416cc237eSreinoud cnp->cn_nameiop == RENAME)) {
78561e8303eSpooka error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
78616cc237eSreinoud if (error) {
78716cc237eSreinoud goto out;
7880c1391f0Schristos }
78916cc237eSreinoud error = EJUSTRETURN;
79016cc237eSreinoud } else {
79116cc237eSreinoud error = ENOENT;
7920c1391f0Schristos }
793cff5e7adSreinoud /* done */
79416cc237eSreinoud goto done;
79516cc237eSreinoud }
79616cc237eSreinoud
79716cc237eSreinoud /*
79816cc237eSreinoud * XXX NOTE tmpfs has a test here that tests that intermediate
79916cc237eSreinoud * components i.e. not the last one ought to be either a directory or
80016cc237eSreinoud * a link. It seems to function well without this code.
80116cc237eSreinoud */
80216cc237eSreinoud
803a0054fd5Sreinoud /* try to create/reuse the node */
804c2e9cb94Sad error = udf_get_node(ump, &icb_loc, &res_node, LK_EXCLUSIVE);
805a0054fd5Sreinoud if (error)
806a0054fd5Sreinoud goto out;
807a0054fd5Sreinoud
8081cabaf0eSreinoud /* check permissions */
80916cc237eSreinoud if (islastcn && (cnp->cn_nameiop == DELETE ||
81016cc237eSreinoud cnp->cn_nameiop == RENAME) ) {
81116cc237eSreinoud error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
812a0054fd5Sreinoud if (error) {
813a0054fd5Sreinoud vput(res_node->vnode);
81416cc237eSreinoud goto out;
815a0054fd5Sreinoud }
81616cc237eSreinoud
8171cabaf0eSreinoud /*
8181cabaf0eSreinoud * Check if the directory has its sticky bit set. If so, ask
8191cabaf0eSreinoud * for clearance since only the owner of a file or directory
8200ac7f4ddSandvar * can remove/rename from that directory.
8211cabaf0eSreinoud */
82216cc237eSreinoud mode = udf_getaccessmode(dir_node);
82316cc237eSreinoud if ((mode & S_ISTXT) != 0) {
8241cabaf0eSreinoud udf_getownership(dir_node, &d_uid, &d_gid);
82516cc237eSreinoud error = kauth_authorize_vnode(cnp->cn_cred,
82616cc237eSreinoud KAUTH_VNODE_DELETE, res_node->vnode,
8279aa2a9c3Schristos dir_node->vnode, genfs_can_sticky(dvp, cnp->cn_cred,
82816cc237eSreinoud d_uid, d_uid));
82916cc237eSreinoud if (error) {
83016cc237eSreinoud error = EPERM;
831a0054fd5Sreinoud vput(res_node->vnode);
83216cc237eSreinoud goto out;
83316cc237eSreinoud }
83416cc237eSreinoud }
83516cc237eSreinoud }
836a0054fd5Sreinoud
837cff5e7adSreinoud *vpp = res_node->vnode;
838cff5e7adSreinoud
83916cc237eSreinoud done:
840cff5e7adSreinoud /*
841cff5e7adSreinoud * Store result in the cache if requested. If we are creating a file,
842cff5e7adSreinoud * the file might not be found and thus putting it into the namecache
843cff5e7adSreinoud * might be seen as negative caching.
844cff5e7adSreinoud */
845d65753d9Srmind if (nameiop != CREATE)
84635ed6905Sdholland cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
84735ed6905Sdholland cnp->cn_flags);
848cff5e7adSreinoud
84916cc237eSreinoud out:
85097834f7bShannken if (error == 0 && *vpp != dvp)
85197834f7bShannken VOP_UNLOCK(*vpp);
85275d2abaeSandvar DPRINTFIF(LOOKUP, error, ("udf_lookup returning error %d\n", error));
853cff5e7adSreinoud
854cff5e7adSreinoud return error;
855cff5e7adSreinoud }
856cff5e7adSreinoud
857cff5e7adSreinoud /* --------------------------------------------------------------------- */
858cff5e7adSreinoud
859cff5e7adSreinoud int
udf_getattr(void * v)860cff5e7adSreinoud udf_getattr(void *v)
861cff5e7adSreinoud {
862cff5e7adSreinoud struct vop_getattr_args /* {
863cff5e7adSreinoud struct vnode *a_vp;
864cff5e7adSreinoud struct vattr *a_vap;
865fc9422c9Selad kauth_cred_t a_cred;
866e979c658Sreinoud struct lwp *a_l;
867cff5e7adSreinoud } */ *ap = v;
868cff5e7adSreinoud struct vnode *vp = ap->a_vp;
869cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
870cff5e7adSreinoud struct udf_mount *ump = udf_node->ump;
871e979c658Sreinoud struct file_entry *fe = udf_node->fe;
872e979c658Sreinoud struct extfile_entry *efe = udf_node->efe;
873a88cc852Sreinoud struct filetimes_extattr_entry *ft_extattr;
874e979c658Sreinoud struct device_extattr_entry *devattr;
875cff5e7adSreinoud struct vattr *vap = ap->a_vap;
876e979c658Sreinoud struct timestamp *atime, *mtime, *attrtime, *creatime;
877cff5e7adSreinoud uint64_t filesize, blkssize;
878e979c658Sreinoud uint32_t nlink;
879a88cc852Sreinoud uint32_t offset, a_l;
880e3b6b345Sreinoud uint8_t *filedata, *targetbuf;
881cff5e7adSreinoud uid_t uid;
882cff5e7adSreinoud gid_t gid;
883e3b6b345Sreinoud int length, error;
884cff5e7adSreinoud
885cff5e7adSreinoud DPRINTF(CALL, ("udf_getattr called\n"));
886cff5e7adSreinoud
887e979c658Sreinoud /* update times before we returning values */
888e979c658Sreinoud udf_itimes(udf_node, NULL, NULL, NULL);
889e979c658Sreinoud
890cff5e7adSreinoud /* get descriptor information */
891e979c658Sreinoud if (fe) {
892cff5e7adSreinoud nlink = udf_rw16(fe->link_cnt);
893cff5e7adSreinoud uid = (uid_t)udf_rw32(fe->uid);
894cff5e7adSreinoud gid = (gid_t)udf_rw32(fe->gid);
895cff5e7adSreinoud filesize = udf_rw64(fe->inf_len);
896cff5e7adSreinoud blkssize = udf_rw64(fe->logblks_rec);
897cff5e7adSreinoud atime = &fe->atime;
898cff5e7adSreinoud mtime = &fe->mtime;
899cff5e7adSreinoud attrtime = &fe->attrtime;
900e979c658Sreinoud filedata = fe->data;
901a88cc852Sreinoud
902a88cc852Sreinoud /* initial guess */
903a88cc852Sreinoud creatime = mtime;
904a88cc852Sreinoud
905a88cc852Sreinoud /* check our extended attribute if present */
906a88cc852Sreinoud error = udf_extattr_search_intern(udf_node,
907a88cc852Sreinoud UDF_FILETIMES_ATTR_NO, "", &offset, &a_l);
908a88cc852Sreinoud if (!error) {
909a88cc852Sreinoud ft_extattr = (struct filetimes_extattr_entry *)
910a88cc852Sreinoud (filedata + offset);
911a88cc852Sreinoud if (ft_extattr->existence & UDF_FILETIMES_FILE_CREATION)
912a88cc852Sreinoud creatime = &ft_extattr->times[0];
913a88cc852Sreinoud }
914cff5e7adSreinoud } else {
915cff5e7adSreinoud assert(udf_node->efe);
916cff5e7adSreinoud nlink = udf_rw16(efe->link_cnt);
917cff5e7adSreinoud uid = (uid_t)udf_rw32(efe->uid);
918cff5e7adSreinoud gid = (gid_t)udf_rw32(efe->gid);
919cff5e7adSreinoud filesize = udf_rw64(efe->inf_len); /* XXX or obj_size? */
920cff5e7adSreinoud blkssize = udf_rw64(efe->logblks_rec);
921cff5e7adSreinoud atime = &efe->atime;
922cff5e7adSreinoud mtime = &efe->mtime;
923cff5e7adSreinoud attrtime = &efe->attrtime;
924e979c658Sreinoud creatime = &efe->ctime;
925e979c658Sreinoud filedata = efe->data;
9260c1391f0Schristos }
927cff5e7adSreinoud
928cff5e7adSreinoud /* do the uid/gid translation game */
9294b1a8129Sreinoud if (uid == (uid_t) -1)
930cff5e7adSreinoud uid = ump->mount_args.anon_uid;
9314b1a8129Sreinoud if (gid == (gid_t) -1)
932cff5e7adSreinoud gid = ump->mount_args.anon_gid;
933cff5e7adSreinoud
934cff5e7adSreinoud /* fill in struct vattr with values from the node */
935c3183f32Spooka vattr_null(vap);
936cff5e7adSreinoud vap->va_type = vp->v_type;
937cff5e7adSreinoud vap->va_mode = udf_getaccessmode(udf_node);
938cff5e7adSreinoud vap->va_nlink = nlink;
939cff5e7adSreinoud vap->va_uid = uid;
940cff5e7adSreinoud vap->va_gid = gid;
941cff5e7adSreinoud vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
942c093c252Sreinoud vap->va_fileid = udf_get_node_id(&udf_node->loc); /* inode hash XXX */
943cff5e7adSreinoud vap->va_size = filesize;
944cff5e7adSreinoud vap->va_blocksize = udf_node->ump->discinfo.sector_size; /* wise? */
945cff5e7adSreinoud
946cff5e7adSreinoud /*
947cff5e7adSreinoud * BUG-ALERT: UDF doesn't count '.' as an entry, so we'll have to add
948cff5e7adSreinoud * 1 to the link count if its a directory we're requested attributes
949cff5e7adSreinoud * of.
950cff5e7adSreinoud */
951cff5e7adSreinoud if (vap->va_type == VDIR)
952cff5e7adSreinoud vap->va_nlink++;
953cff5e7adSreinoud
954e3b6b345Sreinoud /*
955e3b6b345Sreinoud * BUG-ALERT: Posix requires the va_size to be pathlength for symbolic
956e3b6b345Sreinoud * links.
957e3b6b345Sreinoud */
958e3b6b345Sreinoud if (vap->va_type == VLNK) {
959e3b6b345Sreinoud /* claim temporary buffers for translation */
960e3b6b345Sreinoud targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK);
961e3b6b345Sreinoud error = udf_do_readlink(udf_node, filesize, targetbuf, &length);
962e3b6b345Sreinoud if (!error) {
963e3b6b345Sreinoud vap->va_size = length;
964e3b6b345Sreinoud KASSERT(length == strlen(targetbuf));
965e3b6b345Sreinoud }
966e3b6b345Sreinoud free(targetbuf, M_UDFTEMP);
967e3b6b345Sreinoud /* XXX return error? */
968e3b6b345Sreinoud }
969e3b6b345Sreinoud
970cff5e7adSreinoud /* access times */
971cff5e7adSreinoud udf_timestamp_to_timespec(ump, atime, &vap->va_atime);
972cff5e7adSreinoud udf_timestamp_to_timespec(ump, mtime, &vap->va_mtime);
973cff5e7adSreinoud udf_timestamp_to_timespec(ump, attrtime, &vap->va_ctime);
974e979c658Sreinoud udf_timestamp_to_timespec(ump, creatime, &vap->va_birthtime);
975cff5e7adSreinoud
976cff5e7adSreinoud vap->va_gen = 1; /* no multiple generations yes (!?) */
977cff5e7adSreinoud vap->va_flags = 0; /* no flags */
9781d48d181Sreinoud vap->va_bytes = blkssize * udf_node->ump->discinfo.sector_size;
979cff5e7adSreinoud vap->va_filerev = 1; /* TODO file revision numbers? */
980e979c658Sreinoud vap->va_vaflags = 0;
981e979c658Sreinoud /* TODO get vaflags from the extended attributes? */
982e979c658Sreinoud
983e979c658Sreinoud if ((vap->va_type == VBLK) || (vap->va_type == VCHR)) {
984e979c658Sreinoud error = udf_extattr_search_intern(udf_node,
985e979c658Sreinoud UDF_DEVICESPEC_ATTR_NO, "",
986a88cc852Sreinoud &offset, &a_l);
987e979c658Sreinoud /* if error, deny access */
988e979c658Sreinoud if (error || (filedata == NULL)) {
989e979c658Sreinoud vap->va_mode = 0; /* or v_type = VNON? */
990e979c658Sreinoud } else {
991e979c658Sreinoud devattr = (struct device_extattr_entry *)
992e979c658Sreinoud filedata + offset;
993e979c658Sreinoud vap->va_rdev = makedev(
994e979c658Sreinoud udf_rw32(devattr->major),
995e979c658Sreinoud udf_rw32(devattr->minor)
996e979c658Sreinoud );
997e979c658Sreinoud /* TODO we could check the implementator */
998e979c658Sreinoud }
999e979c658Sreinoud }
1000cff5e7adSreinoud
1001cff5e7adSreinoud return 0;
1002cff5e7adSreinoud }
1003cff5e7adSreinoud
1004cff5e7adSreinoud /* --------------------------------------------------------------------- */
1005cff5e7adSreinoud
1006e979c658Sreinoud static int
udf_chown(struct vnode * vp,uid_t new_uid,gid_t new_gid,kauth_cred_t cred)1007e979c658Sreinoud udf_chown(struct vnode *vp, uid_t new_uid, gid_t new_gid,
1008e979c658Sreinoud kauth_cred_t cred)
1009e979c658Sreinoud {
1010e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1011386808d4Selad uid_t uid;
1012386808d4Selad gid_t gid;
1013e979c658Sreinoud int error;
1014e979c658Sreinoud
1015e979c658Sreinoud #ifdef notyet
1016e979c658Sreinoud /* TODO get vaflags from the extended attributes? */
1017e979c658Sreinoud /* Immutable or append-only files cannot be modified, either. */
1018e979c658Sreinoud if (udf_node->flags & (IMMUTABLE | APPEND))
1019e979c658Sreinoud return EPERM;
1020e979c658Sreinoud #endif
1021e979c658Sreinoud
1022e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1023e979c658Sreinoud return EROFS;
1024e979c658Sreinoud
1025e979c658Sreinoud /* retrieve old values */
1026e979c658Sreinoud udf_getownership(udf_node, &uid, &gid);
1027e979c658Sreinoud
1028e979c658Sreinoud /* only one could be specified */
1029e979c658Sreinoud if (new_uid == VNOVAL)
1030e979c658Sreinoud new_uid = uid;
1031e979c658Sreinoud if (new_gid == VNOVAL)
1032e979c658Sreinoud new_gid = gid;
1033e979c658Sreinoud
1034e979c658Sreinoud /* check if we can fit it in an 32 bits */
10357cbe9b45Sreinoud if ((uid_t) ((uint32_t) new_uid) != new_uid)
1036e979c658Sreinoud return EINVAL;
10377cbe9b45Sreinoud if ((gid_t) ((uint32_t) new_gid) != new_gid)
1038e979c658Sreinoud return EINVAL;
1039e979c658Sreinoud
1040e979c658Sreinoud /* check permissions */
10410c9d8d15Selad error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP,
10429aa2a9c3Schristos vp, NULL, genfs_can_chown(vp, cred, uid, gid, new_uid, new_gid));
1043386808d4Selad if (error)
1044386808d4Selad return (error);
1045e979c658Sreinoud
1046e979c658Sreinoud /* change the ownership */
1047e979c658Sreinoud udf_setownership(udf_node, new_uid, new_gid);
1048e979c658Sreinoud
1049e979c658Sreinoud /* mark node changed */
1050e979c658Sreinoud udf_node->i_flags |= IN_CHANGE;
1051e979c658Sreinoud
1052e979c658Sreinoud return 0;
1053e979c658Sreinoud }
1054e979c658Sreinoud
1055e979c658Sreinoud
1056e979c658Sreinoud static int
udf_chmod(struct vnode * vp,mode_t mode,kauth_cred_t cred)1057e979c658Sreinoud udf_chmod(struct vnode *vp, mode_t mode, kauth_cred_t cred)
1058e979c658Sreinoud {
1059e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1060386808d4Selad uid_t uid;
1061386808d4Selad gid_t gid;
1062e979c658Sreinoud int error;
1063e979c658Sreinoud
1064e979c658Sreinoud #ifdef notyet
1065e979c658Sreinoud /* TODO get vaflags from the extended attributes? */
1066e979c658Sreinoud /* Immutable or append-only files cannot be modified, either. */
1067e979c658Sreinoud if (udf_node->flags & (IMMUTABLE | APPEND))
1068e979c658Sreinoud return EPERM;
1069e979c658Sreinoud #endif
1070e979c658Sreinoud
1071e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1072e979c658Sreinoud return EROFS;
1073e979c658Sreinoud
1074e979c658Sreinoud /* retrieve uid/gid values */
1075e979c658Sreinoud udf_getownership(udf_node, &uid, &gid);
1076e979c658Sreinoud
1077e979c658Sreinoud /* check permissions */
10780c9d8d15Selad error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
10799aa2a9c3Schristos NULL, genfs_can_chmod(vp, cred, uid, gid, mode));
1080386808d4Selad if (error)
1081386808d4Selad return (error);
1082e979c658Sreinoud
1083e979c658Sreinoud /* change mode */
1084e979c658Sreinoud udf_setaccessmode(udf_node, mode);
1085e979c658Sreinoud
1086e979c658Sreinoud /* mark node changed */
1087e979c658Sreinoud udf_node->i_flags |= IN_CHANGE;
1088e979c658Sreinoud
1089e979c658Sreinoud return 0;
1090e979c658Sreinoud }
1091e979c658Sreinoud
1092e979c658Sreinoud
1093e979c658Sreinoud /* exported */
1094e979c658Sreinoud int
udf_chsize(struct vnode * vp,u_quad_t newsize,kauth_cred_t cred)1095e979c658Sreinoud udf_chsize(struct vnode *vp, u_quad_t newsize, kauth_cred_t cred)
1096e979c658Sreinoud {
1097e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1098e979c658Sreinoud int error, extended;
1099e979c658Sreinoud
1100e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1101e979c658Sreinoud return EROFS;
1102e979c658Sreinoud
1103e979c658Sreinoud /* Decide whether this is a valid operation based on the file type. */
1104e979c658Sreinoud switch (vp->v_type) {
1105e979c658Sreinoud case VDIR:
1106e979c658Sreinoud return EISDIR;
1107e979c658Sreinoud case VREG:
1108e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1109e979c658Sreinoud return EROFS;
1110e979c658Sreinoud break;
1111e979c658Sreinoud case VBLK:
1112e979c658Sreinoud /* FALLTHROUGH */
1113e979c658Sreinoud case VCHR:
1114e979c658Sreinoud /* FALLTHROUGH */
1115e979c658Sreinoud case VFIFO:
1116e979c658Sreinoud /* Allow modifications of special files even if in the file
1117e979c658Sreinoud * system is mounted read-only (we are not modifying the
1118e979c658Sreinoud * files themselves, but the objects they represent). */
1119e979c658Sreinoud return 0;
1120e979c658Sreinoud default:
1121e979c658Sreinoud /* Anything else is unsupported. */
1122e979c658Sreinoud return EOPNOTSUPP;
1123e979c658Sreinoud }
1124e979c658Sreinoud
1125e979c658Sreinoud #if notyet
1126e979c658Sreinoud /* TODO get vaflags from the extended attributes? */
1127e979c658Sreinoud /* Immutable or append-only files cannot be modified, either. */
1128e979c658Sreinoud if (node->flags & (IMMUTABLE | APPEND))
1129e979c658Sreinoud return EPERM;
1130e979c658Sreinoud #endif
1131e979c658Sreinoud
1132e979c658Sreinoud /* resize file to the requested size */
1133e979c658Sreinoud error = udf_resize_node(udf_node, newsize, &extended);
1134e979c658Sreinoud
1135e979c658Sreinoud if (error == 0) {
1136e979c658Sreinoud /* mark change */
1137e979c658Sreinoud udf_node->i_flags |= IN_CHANGE | IN_MODIFY;
1138d11ea3eaSchristos if (vp->v_mount->mnt_flag & MNT_RELATIME)
1139d11ea3eaSchristos udf_node->i_flags |= IN_ACCESS;
11409d15fe51Sreinoud udf_update(vp, NULL, NULL, NULL, 0);
1141e979c658Sreinoud }
1142e979c658Sreinoud
1143e979c658Sreinoud return error;
1144e979c658Sreinoud }
1145e979c658Sreinoud
1146e979c658Sreinoud
1147e979c658Sreinoud static int
udf_chflags(struct vnode * vp,mode_t mode,kauth_cred_t cred)1148e979c658Sreinoud udf_chflags(struct vnode *vp, mode_t mode, kauth_cred_t cred)
1149e979c658Sreinoud {
1150e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1151e979c658Sreinoud return EROFS;
1152e979c658Sreinoud
1153d2126d96Sreinoud /*
1154d2126d96Sreinoud * XXX we can't do this yet, as its not described in the standard yet
1155d2126d96Sreinoud */
1156e979c658Sreinoud
1157d2126d96Sreinoud return EOPNOTSUPP;
1158e979c658Sreinoud }
1159e979c658Sreinoud
1160e979c658Sreinoud
1161e979c658Sreinoud static int
udf_chtimes(struct vnode * vp,struct timespec * atime,struct timespec * mtime,struct timespec * birthtime,int setattrflags,kauth_cred_t cred)1162e979c658Sreinoud udf_chtimes(struct vnode *vp,
1163e979c658Sreinoud struct timespec *atime, struct timespec *mtime,
1164e979c658Sreinoud struct timespec *birthtime, int setattrflags,
1165e979c658Sreinoud kauth_cred_t cred)
1166e979c658Sreinoud {
1167e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1168863a01b5Selad uid_t uid;
1169e979c658Sreinoud gid_t gid;
1170e979c658Sreinoud int error;
1171e979c658Sreinoud
1172e979c658Sreinoud #ifdef notyet
1173e979c658Sreinoud /* TODO get vaflags from the extended attributes? */
1174e979c658Sreinoud /* Immutable or append-only files cannot be modified, either. */
1175e979c658Sreinoud if (udf_node->flags & (IMMUTABLE | APPEND))
1176e979c658Sreinoud return EPERM;
1177e979c658Sreinoud #endif
1178e979c658Sreinoud
1179e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
1180e979c658Sreinoud return EROFS;
1181e979c658Sreinoud
1182e979c658Sreinoud /* retrieve uid/gid values */
1183e979c658Sreinoud udf_getownership(udf_node, &uid, &gid);
1184e979c658Sreinoud
1185e979c658Sreinoud /* check permissions */
11860c9d8d15Selad error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
11879aa2a9c3Schristos NULL, genfs_can_chtimes(vp, cred, uid, setattrflags));
1188e979c658Sreinoud if (error)
1189863a01b5Selad return (error);
1190e979c658Sreinoud
1191e979c658Sreinoud /* update node flags depending on what times are passed */
1192e979c658Sreinoud if (atime->tv_sec != VNOVAL)
1193e979c658Sreinoud if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
1194e979c658Sreinoud udf_node->i_flags |= IN_ACCESS;
1195d11ea3eaSchristos if ((mtime->tv_sec != VNOVAL) || (birthtime->tv_sec != VNOVAL)) {
1196e979c658Sreinoud udf_node->i_flags |= IN_CHANGE | IN_UPDATE;
1197d11ea3eaSchristos if (vp->v_mount->mnt_flag & MNT_RELATIME)
1198d11ea3eaSchristos udf_node->i_flags |= IN_ACCESS;
1199d11ea3eaSchristos }
1200e979c658Sreinoud
12019d15fe51Sreinoud return udf_update(vp, atime, mtime, birthtime, 0);
1202e979c658Sreinoud }
1203e979c658Sreinoud
1204e979c658Sreinoud
1205cff5e7adSreinoud int
udf_setattr(void * v)1206cff5e7adSreinoud udf_setattr(void *v)
1207cff5e7adSreinoud {
1208cff5e7adSreinoud struct vop_setattr_args /* {
1209cff5e7adSreinoud struct vnode *a_vp;
1210cff5e7adSreinoud struct vattr *a_vap;
1211fc9422c9Selad kauth_cred_t a_cred;
1212e979c658Sreinoud struct lwp *a_l;
1213cff5e7adSreinoud } */ *ap = v;
1214cff5e7adSreinoud struct vnode *vp = ap->a_vp;
1215e979c658Sreinoud /* struct udf_node *udf_node = VTOI(vp); */
1216e979c658Sreinoud /* struct udf_mount *ump = udf_node->ump; */
1217e979c658Sreinoud kauth_cred_t cred = ap->a_cred;
1218cff5e7adSreinoud struct vattr *vap = ap->a_vap;
1219e979c658Sreinoud int error;
1220cff5e7adSreinoud
1221e979c658Sreinoud DPRINTF(CALL, ("udf_setattr called\n"));
1222cff5e7adSreinoud
1223e979c658Sreinoud /* Abort if any unsettable attribute is given. */
1224e979c658Sreinoud error = 0;
1225e979c658Sreinoud if (vap->va_type != VNON ||
1226e979c658Sreinoud vap->va_nlink != VNOVAL ||
1227e979c658Sreinoud vap->va_fsid != VNOVAL ||
1228e979c658Sreinoud vap->va_fileid != VNOVAL ||
1229e979c658Sreinoud vap->va_blocksize != VNOVAL ||
1230e979c658Sreinoud #ifdef notyet
12319d15fe51Sreinoud /* checks are debated */
1232e979c658Sreinoud vap->va_ctime.tv_sec != VNOVAL ||
1233e979c658Sreinoud vap->va_ctime.tv_nsec != VNOVAL ||
1234e979c658Sreinoud vap->va_birthtime.tv_sec != VNOVAL ||
1235e979c658Sreinoud vap->va_birthtime.tv_nsec != VNOVAL ||
12369d15fe51Sreinoud #endif
1237e979c658Sreinoud vap->va_gen != VNOVAL ||
1238e979c658Sreinoud vap->va_rdev != VNOVAL ||
1239e979c658Sreinoud vap->va_bytes != VNOVAL)
1240e979c658Sreinoud error = EINVAL;
1241cff5e7adSreinoud
1242e979c658Sreinoud DPRINTF(ATTR, ("setattr changing:\n"));
1243e979c658Sreinoud if (error == 0 && (vap->va_flags != VNOVAL)) {
1244e979c658Sreinoud DPRINTF(ATTR, ("\tchflags\n"));
1245e979c658Sreinoud error = udf_chflags(vp, vap->va_flags, cred);
12460c1391f0Schristos }
1247cff5e7adSreinoud
1248e979c658Sreinoud if (error == 0 && (vap->va_size != VNOVAL)) {
1249e979c658Sreinoud DPRINTF(ATTR, ("\tchsize\n"));
1250e979c658Sreinoud error = udf_chsize(vp, vap->va_size, cred);
1251e979c658Sreinoud }
1252e979c658Sreinoud
1253e979c658Sreinoud if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) {
1254e979c658Sreinoud DPRINTF(ATTR, ("\tchown\n"));
1255e979c658Sreinoud error = udf_chown(vp, vap->va_uid, vap->va_gid, cred);
1256e979c658Sreinoud }
1257e979c658Sreinoud
1258e979c658Sreinoud if (error == 0 && (vap->va_mode != VNOVAL)) {
1259e979c658Sreinoud DPRINTF(ATTR, ("\tchmod\n"));
1260e979c658Sreinoud error = udf_chmod(vp, vap->va_mode, cred);
1261e979c658Sreinoud }
1262e979c658Sreinoud
1263e979c658Sreinoud if (error == 0 &&
1264e979c658Sreinoud ((vap->va_atime.tv_sec != VNOVAL &&
1265e979c658Sreinoud vap->va_atime.tv_nsec != VNOVAL) ||
1266e979c658Sreinoud (vap->va_mtime.tv_sec != VNOVAL &&
1267e979c658Sreinoud vap->va_mtime.tv_nsec != VNOVAL))
1268e979c658Sreinoud ) {
1269e979c658Sreinoud DPRINTF(ATTR, ("\tchtimes\n"));
1270e979c658Sreinoud error = udf_chtimes(vp, &vap->va_atime, &vap->va_mtime,
1271e979c658Sreinoud &vap->va_birthtime, vap->va_vaflags, cred);
1272e979c658Sreinoud }
1273e979c658Sreinoud
1274e979c658Sreinoud return error;
1275cff5e7adSreinoud }
1276cff5e7adSreinoud
1277cff5e7adSreinoud /* --------------------------------------------------------------------- */
1278cff5e7adSreinoud
1279cff5e7adSreinoud /*
1280cff5e7adSreinoud * Return POSIX pathconf information for UDF file systems.
1281cff5e7adSreinoud */
1282cff5e7adSreinoud int
udf_pathconf(void * v)1283cff5e7adSreinoud udf_pathconf(void *v)
1284cff5e7adSreinoud {
1285cff5e7adSreinoud struct vop_pathconf_args /* {
1286cff5e7adSreinoud struct vnode *a_vp;
1287cff5e7adSreinoud int a_name;
1288cff5e7adSreinoud register_t *a_retval;
1289cff5e7adSreinoud } */ *ap = v;
1290cff5e7adSreinoud uint32_t bits;
1291cff5e7adSreinoud
1292cff5e7adSreinoud DPRINTF(CALL, ("udf_pathconf called\n"));
1293cff5e7adSreinoud
1294cff5e7adSreinoud switch (ap->a_name) {
1295cff5e7adSreinoud case _PC_LINK_MAX:
1296cff5e7adSreinoud *ap->a_retval = (1<<16)-1; /* 16 bits */
1297cff5e7adSreinoud return 0;
1298cff5e7adSreinoud case _PC_NAME_MAX:
12992fcd0204Schristos *ap->a_retval = UDF_MAXNAMLEN;
1300cff5e7adSreinoud return 0;
1301cff5e7adSreinoud case _PC_PATH_MAX:
1302cff5e7adSreinoud *ap->a_retval = PATH_MAX;
1303cff5e7adSreinoud return 0;
1304cff5e7adSreinoud case _PC_PIPE_BUF:
1305cff5e7adSreinoud *ap->a_retval = PIPE_BUF;
1306cff5e7adSreinoud return 0;
1307cff5e7adSreinoud case _PC_CHOWN_RESTRICTED:
1308cff5e7adSreinoud *ap->a_retval = 1;
1309cff5e7adSreinoud return 0;
1310cff5e7adSreinoud case _PC_NO_TRUNC:
1311cff5e7adSreinoud *ap->a_retval = 1;
1312cff5e7adSreinoud return 0;
1313cff5e7adSreinoud case _PC_SYNC_IO:
1314cff5e7adSreinoud *ap->a_retval = 0; /* synchronised is off for performance */
1315cff5e7adSreinoud return 0;
1316cff5e7adSreinoud case _PC_FILESIZEBITS:
1317e979c658Sreinoud /* 64 bit file offsets -> 2+floor(2log(2^64-1)) = 2 + 63 = 65 */
1318e979c658Sreinoud bits = 64; /* XXX ought to deliver 65 */
1319e979c658Sreinoud #if 0
1320cff5e7adSreinoud if (udf_node)
1321e979c658Sreinoud bits = 64 * vp->v_mount->mnt_dev_bshift;
1322e979c658Sreinoud #endif
1323cff5e7adSreinoud *ap->a_retval = bits;
1324cff5e7adSreinoud return 0;
132579e3c74fSchristos default:
132679e3c74fSchristos return genfs_pathconf(ap);
13270c1391f0Schristos }
1328cff5e7adSreinoud }
1329cff5e7adSreinoud
1330cff5e7adSreinoud
1331cff5e7adSreinoud /* --------------------------------------------------------------------- */
1332cff5e7adSreinoud
1333cff5e7adSreinoud int
udf_open(void * v)1334cff5e7adSreinoud udf_open(void *v)
1335cff5e7adSreinoud {
1336cff5e7adSreinoud struct vop_open_args /* {
1337cff5e7adSreinoud struct vnode *a_vp;
1338cff5e7adSreinoud int a_mode;
1339fc9422c9Selad kauth_cred_t a_cred;
1340cff5e7adSreinoud struct proc *a_p;
13414d595fd7Schristos } */ *ap = v;
1342e979c658Sreinoud int flags;
1343cff5e7adSreinoud
1344cff5e7adSreinoud DPRINTF(CALL, ("udf_open called\n"));
1345e979c658Sreinoud
1346e979c658Sreinoud /*
1347e979c658Sreinoud * Files marked append-only must be opened for appending.
134809fb1792Sandvar * TODO: get chflags(2) flags from extended attribute.
1349e979c658Sreinoud */
1350e979c658Sreinoud flags = 0;
1351e979c658Sreinoud if ((flags & APPEND) && (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
1352e979c658Sreinoud return (EPERM);
1353cff5e7adSreinoud
1354cff5e7adSreinoud return 0;
1355cff5e7adSreinoud }
1356cff5e7adSreinoud
1357cff5e7adSreinoud
1358cff5e7adSreinoud /* --------------------------------------------------------------------- */
1359cff5e7adSreinoud
1360cff5e7adSreinoud int
udf_close(void * v)1361cff5e7adSreinoud udf_close(void *v)
1362cff5e7adSreinoud {
1363cff5e7adSreinoud struct vop_close_args /* {
1364cff5e7adSreinoud struct vnode *a_vp;
1365cff5e7adSreinoud int a_fflag;
1366fc9422c9Selad kauth_cred_t a_cred;
1367cff5e7adSreinoud struct proc *a_p;
1368cff5e7adSreinoud } */ *ap = v;
1369cff5e7adSreinoud struct vnode *vp = ap->a_vp;
1370cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
1371c1a508d1Sreinoud int async = vp->v_mount->mnt_flag & MNT_ASYNC;
1372c1a508d1Sreinoud int error;
1373cff5e7adSreinoud
1374cff5e7adSreinoud DPRINTF(CALL, ("udf_close called\n"));
1375cff5e7adSreinoud udf_node = udf_node; /* shut up gcc */
1376cff5e7adSreinoud
1377c1a508d1Sreinoud if (!async && (vp->v_type != VDIR)) {
1378d2a0ebb6Sad rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
1379c1a508d1Sreinoud error = VOP_PUTPAGES(vp, 0, 0, PGO_CLEANIT);
1380c1a508d1Sreinoud if (error)
1381c1a508d1Sreinoud return error;
1382c1a508d1Sreinoud }
1383c1a508d1Sreinoud
1384e225b7bdSrmind mutex_enter(vp->v_interlock);
138523bf8800Sad if (vrefcnt(vp) > 1)
1386e979c658Sreinoud udf_itimes(udf_node, NULL, NULL, NULL);
1387e225b7bdSrmind mutex_exit(vp->v_interlock);
1388cff5e7adSreinoud
1389cff5e7adSreinoud return 0;
1390cff5e7adSreinoud }
1391cff5e7adSreinoud
1392cff5e7adSreinoud
1393cff5e7adSreinoud /* --------------------------------------------------------------------- */
1394cff5e7adSreinoud
1395009f5d2fSelad static int
udf_check_possible(struct vnode * vp,struct vattr * vap,mode_t mode)1396c13b143eSpgoyette udf_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode)
1397cff5e7adSreinoud {
1398e979c658Sreinoud int flags;
1399cff5e7adSreinoud
1400cff5e7adSreinoud /* check if we are allowed to write */
1401009f5d2fSelad switch (vap->va_type) {
1402cff5e7adSreinoud case VDIR:
1403cff5e7adSreinoud case VLNK:
1404cff5e7adSreinoud case VREG:
1405cff5e7adSreinoud /*
1406cff5e7adSreinoud * normal nodes: check if we're on a read-only mounted
1407cff5e7adSreinoud * filingsystem and bomb out if we're trying to write.
1408cff5e7adSreinoud */
1409cff5e7adSreinoud if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
1410cff5e7adSreinoud return EROFS;
1411cff5e7adSreinoud break;
1412cff5e7adSreinoud case VBLK:
1413cff5e7adSreinoud case VCHR:
1414cff5e7adSreinoud case VSOCK:
1415cff5e7adSreinoud case VFIFO:
1416cff5e7adSreinoud /*
1417cff5e7adSreinoud * special nodes: even on read-only mounted filingsystems
1418cff5e7adSreinoud * these are allowed to be written to if permissions allow.
1419cff5e7adSreinoud */
1420cff5e7adSreinoud break;
1421cff5e7adSreinoud default:
1422cff5e7adSreinoud /* no idea what this is */
1423cff5e7adSreinoud return EINVAL;
1424cff5e7adSreinoud }
1425cff5e7adSreinoud
1426e979c658Sreinoud /* noone may write immutable files */
142709fb1792Sandvar /* TODO: get chflags(2) flags from extended attribute. */
1428e979c658Sreinoud flags = 0;
1429e979c658Sreinoud if ((mode & VWRITE) && (flags & IMMUTABLE))
1430e979c658Sreinoud return EPERM;
1431cff5e7adSreinoud
1432009f5d2fSelad return 0;
1433009f5d2fSelad }
1434009f5d2fSelad
1435009f5d2fSelad static int
udf_check_permitted(struct vnode * vp,struct vattr * vap,accmode_t accmode,kauth_cred_t cred)14369aa2a9c3Schristos udf_check_permitted(struct vnode *vp, struct vattr *vap, accmode_t accmode,
1437009f5d2fSelad kauth_cred_t cred)
1438009f5d2fSelad {
143987092026Selad /* ask the generic genfs_can_access to advice on security */
14409aa2a9c3Schristos return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
14419aa2a9c3Schristos vp->v_type, vap->va_mode), vp, NULL, genfs_can_access(vp, cred,
14429aa2a9c3Schristos vap->va_uid, vap->va_gid, vap->va_mode, NULL, accmode));
1443cff5e7adSreinoud }
1444cff5e7adSreinoud
1445009f5d2fSelad int
udf_access(void * v)1446009f5d2fSelad udf_access(void *v)
1447009f5d2fSelad {
1448009f5d2fSelad struct vop_access_args /* {
1449009f5d2fSelad struct vnode *a_vp;
14509aa2a9c3Schristos accmode_t a_accmode;
1451009f5d2fSelad kauth_cred_t a_cred;
1452009f5d2fSelad struct proc *a_p;
1453009f5d2fSelad } */ *ap = v;
1454009f5d2fSelad struct vnode *vp = ap->a_vp;
14559aa2a9c3Schristos accmode_t accmode = ap->a_accmode;
1456009f5d2fSelad kauth_cred_t cred = ap->a_cred;
1457009f5d2fSelad /* struct udf_node *udf_node = VTOI(vp); */
1458009f5d2fSelad struct vattr vap;
1459009f5d2fSelad int error;
1460009f5d2fSelad
1461009f5d2fSelad DPRINTF(CALL, ("udf_access called\n"));
1462009f5d2fSelad
1463009f5d2fSelad error = VOP_GETATTR(vp, &vap, NULL);
1464009f5d2fSelad if (error)
1465009f5d2fSelad return error;
1466009f5d2fSelad
14679aa2a9c3Schristos error = udf_check_possible(vp, &vap, accmode);
1468009f5d2fSelad if (error)
1469009f5d2fSelad return error;
1470009f5d2fSelad
14719aa2a9c3Schristos error = udf_check_permitted(vp, &vap, accmode, cred);
1472009f5d2fSelad
1473009f5d2fSelad return error;
1474009f5d2fSelad }
1475009f5d2fSelad
1476cff5e7adSreinoud /* --------------------------------------------------------------------- */
1477cff5e7adSreinoud
1478cff5e7adSreinoud int
udf_create(void * v)1479cff5e7adSreinoud udf_create(void *v)
1480cff5e7adSreinoud {
148104c776e5Shannken struct vop_create_v3_args /* {
1482cff5e7adSreinoud struct vnode *a_dvp;
1483cff5e7adSreinoud struct vnode **a_vpp;
1484cff5e7adSreinoud struct componentname *a_cnp;
1485cff5e7adSreinoud struct vattr *a_vap;
1486cff5e7adSreinoud } */ *ap = v;
1487e979c658Sreinoud struct vnode *dvp = ap->a_dvp;
1488e979c658Sreinoud struct vnode **vpp = ap->a_vpp;
1489e979c658Sreinoud struct vattr *vap = ap->a_vap;
1490cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
1491e979c658Sreinoud int error;
1492cff5e7adSreinoud
1493e979c658Sreinoud DPRINTF(CALL, ("udf_create called\n"));
1494e979c658Sreinoud error = udf_create_node(dvp, vpp, vap, cnp);
1495cff5e7adSreinoud
1496e979c658Sreinoud return error;
1497cff5e7adSreinoud }
1498cff5e7adSreinoud
1499cff5e7adSreinoud /* --------------------------------------------------------------------- */
1500cff5e7adSreinoud
1501cff5e7adSreinoud int
udf_mknod(void * v)1502cff5e7adSreinoud udf_mknod(void *v)
1503cff5e7adSreinoud {
150404c776e5Shannken struct vop_mknod_v3_args /* {
1505cff5e7adSreinoud struct vnode *a_dvp;
1506cff5e7adSreinoud struct vnode **a_vpp;
1507cff5e7adSreinoud struct componentname *a_cnp;
1508cff5e7adSreinoud struct vattr *a_vap;
1509cff5e7adSreinoud } */ *ap = v;
1510e979c658Sreinoud struct vnode *dvp = ap->a_dvp;
1511e979c658Sreinoud struct vnode **vpp = ap->a_vpp;
1512e979c658Sreinoud struct vattr *vap = ap->a_vap;
1513e979c658Sreinoud struct componentname *cnp = ap->a_cnp;
1514e979c658Sreinoud int error;
1515cff5e7adSreinoud
1516e979c658Sreinoud DPRINTF(CALL, ("udf_mknod called\n"));
1517e979c658Sreinoud error = udf_create_node(dvp, vpp, vap, cnp);
1518cff5e7adSreinoud
1519e979c658Sreinoud return error;
1520cff5e7adSreinoud }
1521cff5e7adSreinoud
1522cff5e7adSreinoud /* --------------------------------------------------------------------- */
1523cff5e7adSreinoud
1524cff5e7adSreinoud int
udf_mkdir(void * v)1525e979c658Sreinoud udf_mkdir(void *v)
1526cff5e7adSreinoud {
152704c776e5Shannken struct vop_mkdir_v3_args /* {
1528cff5e7adSreinoud struct vnode *a_dvp;
1529e979c658Sreinoud struct vnode **a_vpp;
1530cff5e7adSreinoud struct componentname *a_cnp;
1531e979c658Sreinoud struct vattr *a_vap;
1532cff5e7adSreinoud } */ *ap = v;
1533cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
1534e979c658Sreinoud struct vnode **vpp = ap->a_vpp;
1535e979c658Sreinoud struct vattr *vap = ap->a_vap;
1536e979c658Sreinoud struct componentname *cnp = ap->a_cnp;
1537e979c658Sreinoud int error;
1538cff5e7adSreinoud
1539e979c658Sreinoud DPRINTF(CALL, ("udf_mkdir called\n"));
1540e979c658Sreinoud error = udf_create_node(dvp, vpp, vap, cnp);
1541cff5e7adSreinoud
1542e979c658Sreinoud return error;
1543cff5e7adSreinoud }
1544cff5e7adSreinoud
1545cff5e7adSreinoud /* --------------------------------------------------------------------- */
1546cff5e7adSreinoud
1547cff5e7adSreinoud int
udf_link(void * v)1548cff5e7adSreinoud udf_link(void *v)
1549cff5e7adSreinoud {
155046e71c7dSriastradh struct vop_link_v2_args /* {
1551cff5e7adSreinoud struct vnode *a_dvp;
1552cff5e7adSreinoud struct vnode *a_vp;
1553cff5e7adSreinoud struct componentname *a_cnp;
1554cff5e7adSreinoud } */ *ap = v;
1555cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
1556cff5e7adSreinoud struct vnode *vp = ap->a_vp;
1557cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
155889513510Schristos struct udf_node *udf_node, *dir_node;
155989513510Schristos struct vattr vap;
156089513510Schristos int error, abrt = 1;
1561cff5e7adSreinoud
156289513510Schristos DPRINTF(CALL, ("udf_link called\n"));
156389513510Schristos KASSERT(dvp != vp);
156489513510Schristos KASSERT(vp->v_type != VDIR);
156589513510Schristos KASSERT(dvp->v_mount == vp->v_mount);
156689513510Schristos
156789513510Schristos /* get attributes */
156889513510Schristos dir_node = VTOI(dvp);
156989513510Schristos udf_node = VTOI(vp);
157089513510Schristos
157189513510Schristos if ((error = vn_lock(vp, LK_EXCLUSIVE))) {
1572a7123e48Sreinoud DPRINTF(LOCKING, ("exclusive lock failed for vnode %p\n", vp));
157389513510Schristos goto out;
157489513510Schristos }
157589513510Schristos
157689513510Schristos error = VOP_GETATTR(vp, &vap, FSCRED);
1577e979c658Sreinoud if (error)
157889513510Schristos goto out1;
1579cff5e7adSreinoud
158089513510Schristos /* check link count overflow */
158189513510Schristos if (vap.va_nlink >= (1<<16)-1) { /* uint16_t */
158289513510Schristos error = EMLINK;
158389513510Schristos goto out1;
158489513510Schristos }
158589513510Schristos error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_ADD_LINK, vp,
158689513510Schristos dvp, 0);
158789513510Schristos if (error)
158889513510Schristos goto out1;
158989513510Schristos abrt = 0;
159089513510Schristos error = udf_dir_attach(dir_node->ump, dir_node, udf_node, &vap, cnp);
159189513510Schristos out1:
159289513510Schristos VOP_UNLOCK(vp);
159389513510Schristos out:
159489513510Schristos if (abrt)
159589513510Schristos VOP_ABORTOP(dvp, cnp);
1596e979c658Sreinoud return error;
1597cff5e7adSreinoud }
1598cff5e7adSreinoud
1599cff5e7adSreinoud /* --------------------------------------------------------------------- */
1600cff5e7adSreinoud
1601e979c658Sreinoud static int
udf_do_symlink(struct udf_node * udf_node,char * target)1602e979c658Sreinoud udf_do_symlink(struct udf_node *udf_node, char *target)
1603e979c658Sreinoud {
1604e979c658Sreinoud struct pathcomp pathcomp;
1605e979c658Sreinoud uint8_t *pathbuf, *pathpos, *compnamepos;
1606e979c658Sreinoud char *mntonname;
1607e979c658Sreinoud int pathlen, len, compnamelen, mntonnamelen;
1608e979c658Sreinoud int error;
1609e979c658Sreinoud
1610e979c658Sreinoud /* process `target' to an UDF structure */
1611e979c658Sreinoud pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK);
1612e979c658Sreinoud pathpos = pathbuf;
1613e979c658Sreinoud pathlen = 0;
1614e979c658Sreinoud
1615e979c658Sreinoud if (*target == '/') {
1616e979c658Sreinoud /* symlink starts from the root */
1617e979c658Sreinoud len = UDF_PATH_COMP_SIZE;
1618e979c658Sreinoud memset(&pathcomp, 0, len);
1619e979c658Sreinoud pathcomp.type = UDF_PATH_COMP_ROOT;
1620e979c658Sreinoud
1621e979c658Sreinoud /* check if its mount-point relative! */
1622e979c658Sreinoud mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1623e979c658Sreinoud mntonnamelen = strlen(mntonname);
1624e979c658Sreinoud if (strlen(target) >= mntonnamelen) {
1625e979c658Sreinoud if (strncmp(target, mntonname, mntonnamelen) == 0) {
1626e979c658Sreinoud pathcomp.type = UDF_PATH_COMP_MOUNTROOT;
1627e979c658Sreinoud target += mntonnamelen;
1628e979c658Sreinoud }
1629e979c658Sreinoud } else {
1630e979c658Sreinoud target++;
1631e979c658Sreinoud }
1632e979c658Sreinoud
1633e979c658Sreinoud memcpy(pathpos, &pathcomp, len);
1634e979c658Sreinoud pathpos += len;
1635e979c658Sreinoud pathlen += len;
1636e979c658Sreinoud }
1637e979c658Sreinoud
1638e979c658Sreinoud error = 0;
1639e979c658Sreinoud while (*target) {
1640e979c658Sreinoud /* ignore multiple '/' */
1641e979c658Sreinoud while (*target == '/') {
1642e979c658Sreinoud target++;
1643e979c658Sreinoud }
1644e979c658Sreinoud if (!*target)
1645e979c658Sreinoud break;
1646e979c658Sreinoud
1647e979c658Sreinoud /* extract component name */
1648e979c658Sreinoud compnamelen = 0;
1649e979c658Sreinoud compnamepos = target;
1650e979c658Sreinoud while ((*target) && (*target != '/')) {
1651e979c658Sreinoud target++;
1652e979c658Sreinoud compnamelen++;
1653e979c658Sreinoud }
1654e979c658Sreinoud
1655e979c658Sreinoud /* just trunc if too long ?? (security issue) */
1656e979c658Sreinoud if (compnamelen >= 127) {
1657e979c658Sreinoud error = ENAMETOOLONG;
1658e979c658Sreinoud break;
1659e979c658Sreinoud }
1660e979c658Sreinoud
1661e979c658Sreinoud /* convert unix name to UDF name */
1662e979c658Sreinoud len = sizeof(struct pathcomp);
1663e979c658Sreinoud memset(&pathcomp, 0, len);
1664e979c658Sreinoud pathcomp.type = UDF_PATH_COMP_NAME;
1665e979c658Sreinoud len = UDF_PATH_COMP_SIZE;
1666e979c658Sreinoud
1667e979c658Sreinoud if ((compnamelen == 2) && (strncmp(compnamepos, "..", 2) == 0))
1668e979c658Sreinoud pathcomp.type = UDF_PATH_COMP_PARENTDIR;
1669e979c658Sreinoud if ((compnamelen == 1) && (*compnamepos == '.'))
1670e979c658Sreinoud pathcomp.type = UDF_PATH_COMP_CURDIR;
1671e979c658Sreinoud
1672e979c658Sreinoud if (pathcomp.type == UDF_PATH_COMP_NAME) {
1673e979c658Sreinoud unix_to_udf_name(
1674e979c658Sreinoud (char *) &pathcomp.ident, &pathcomp.l_ci,
1675e979c658Sreinoud compnamepos, compnamelen,
1676e979c658Sreinoud &udf_node->ump->logical_vol->desc_charset);
1677e979c658Sreinoud len = UDF_PATH_COMP_SIZE + pathcomp.l_ci;
1678e979c658Sreinoud }
1679e979c658Sreinoud
1680e979c658Sreinoud if (pathlen + len >= UDF_SYMLINKBUFLEN) {
1681e979c658Sreinoud error = ENAMETOOLONG;
1682e979c658Sreinoud break;
1683e979c658Sreinoud }
1684e979c658Sreinoud
1685e979c658Sreinoud memcpy(pathpos, &pathcomp, len);
1686e979c658Sreinoud pathpos += len;
1687e979c658Sreinoud pathlen += len;
1688e979c658Sreinoud }
1689e979c658Sreinoud
1690e979c658Sreinoud if (error) {
1691183889cbSandvar /* apparently too big */
1692e979c658Sreinoud free(pathbuf, M_UDFTEMP);
1693e979c658Sreinoud return error;
1694e979c658Sreinoud }
1695e979c658Sreinoud
1696e979c658Sreinoud error = udf_grow_node(udf_node, pathlen);
1697e979c658Sreinoud if (error) {
1698e979c658Sreinoud /* failed to pregrow node */
1699e979c658Sreinoud free(pathbuf, M_UDFTEMP);
1700e979c658Sreinoud return error;
1701e979c658Sreinoud }
1702e979c658Sreinoud
1703e979c658Sreinoud /* write out structure on the new file */
1704e979c658Sreinoud error = vn_rdwr(UIO_WRITE, udf_node->vnode,
1705e979c658Sreinoud pathbuf, pathlen, 0,
17068188ee76Shannken UIO_SYSSPACE, IO_ALTSEMANTICS,
1707e979c658Sreinoud FSCRED, NULL, NULL);
1708a3665ba5Sreinoud
1709a3665ba5Sreinoud /* return status of symlink contents writeout */
1710e979c658Sreinoud free(pathbuf, M_UDFTEMP);
1711e979c658Sreinoud return error;
1712e979c658Sreinoud }
1713e979c658Sreinoud
1714e979c658Sreinoud
1715cff5e7adSreinoud int
udf_symlink(void * v)1716cff5e7adSreinoud udf_symlink(void *v)
1717cff5e7adSreinoud {
171804c776e5Shannken struct vop_symlink_v3_args /* {
1719cff5e7adSreinoud struct vnode *a_dvp;
1720cff5e7adSreinoud struct vnode **a_vpp;
1721cff5e7adSreinoud struct componentname *a_cnp;
1722cff5e7adSreinoud struct vattr *a_vap;
1723cff5e7adSreinoud char *a_target;
1724cff5e7adSreinoud } */ *ap = v;
1725cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
1726e979c658Sreinoud struct vnode **vpp = ap->a_vpp;
1727e979c658Sreinoud struct vattr *vap = ap->a_vap;
1728cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
1729e979c658Sreinoud struct udf_node *dir_node;
1730e979c658Sreinoud struct udf_node *udf_node;
1731e979c658Sreinoud int error;
1732cff5e7adSreinoud
1733e979c658Sreinoud DPRINTF(CALL, ("udf_symlink called\n"));
1734e979c658Sreinoud DPRINTF(CALL, ("\tlinking to `%s`\n", ap->a_target));
1735e979c658Sreinoud error = udf_create_node(dvp, vpp, vap, cnp);
1736e979c658Sreinoud KASSERT(((error == 0) && (*vpp != NULL)) || ((error && (*vpp == NULL))));
1737e979c658Sreinoud if (!error) {
1738e979c658Sreinoud dir_node = VTOI(dvp);
1739e979c658Sreinoud udf_node = VTOI(*vpp);
1740e979c658Sreinoud KASSERT(udf_node);
1741e979c658Sreinoud error = udf_do_symlink(udf_node, ap->a_target);
1742e979c658Sreinoud if (error) {
1743e979c658Sreinoud /* remove node */
1744e979c658Sreinoud udf_dir_detach(udf_node->ump, dir_node, udf_node, cnp);
17455d76927eSreinoud vrele(*vpp);
17465d76927eSreinoud *vpp = NULL;
1747e979c658Sreinoud }
1748e979c658Sreinoud }
1749e979c658Sreinoud return error;
1750cff5e7adSreinoud }
1751cff5e7adSreinoud
1752cff5e7adSreinoud /* --------------------------------------------------------------------- */
1753cff5e7adSreinoud
1754e3b6b345Sreinoud static int
udf_do_readlink(struct udf_node * udf_node,uint64_t filesize,uint8_t * targetbuf,int * length)1755e3b6b345Sreinoud udf_do_readlink(struct udf_node *udf_node, uint64_t filesize,
1756e3b6b345Sreinoud uint8_t *targetbuf, int *length)
1757cff5e7adSreinoud {
1758e979c658Sreinoud struct pathcomp pathcomp;
1759e3b6b345Sreinoud uint8_t *pathbuf, *tmpname;
1760e979c658Sreinoud uint8_t *pathpos, *targetpos;
1761e979c658Sreinoud char *mntonname;
1762e979c658Sreinoud int pathlen, targetlen, namelen, mntonnamelen, len, l_ci;
1763e979c658Sreinoud int first, error;
1764cff5e7adSreinoud
1765e979c658Sreinoud pathbuf = malloc(UDF_SYMLINKBUFLEN, M_UDFTEMP, M_WAITOK);
1766e979c658Sreinoud tmpname = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK);
1767e979c658Sreinoud memset(pathbuf, 0, UDF_SYMLINKBUFLEN);
1768e979c658Sreinoud memset(targetbuf, 0, PATH_MAX);
1769e979c658Sreinoud
1770e979c658Sreinoud /* read contents of file in our temporary buffer */
1771e979c658Sreinoud error = vn_rdwr(UIO_READ, udf_node->vnode,
1772e3b6b345Sreinoud pathbuf, filesize, 0,
1773e979c658Sreinoud UIO_SYSSPACE, IO_NODELOCKED | IO_ALTSEMANTICS,
1774e979c658Sreinoud FSCRED, NULL, NULL);
1775e979c658Sreinoud if (error) {
1776e979c658Sreinoud /* failed to read in symlink contents */
1777e979c658Sreinoud free(pathbuf, M_UDFTEMP);
1778e979c658Sreinoud free(tmpname, M_UDFTEMP);
1779e979c658Sreinoud return error;
1780e979c658Sreinoud }
1781e979c658Sreinoud
1782e979c658Sreinoud /* convert to a unix path */
1783e979c658Sreinoud pathpos = pathbuf;
1784e979c658Sreinoud pathlen = 0;
1785e979c658Sreinoud targetpos = targetbuf;
1786e979c658Sreinoud targetlen = PATH_MAX;
1787e979c658Sreinoud mntonname = udf_node->ump->vfs_mountp->mnt_stat.f_mntonname;
1788e979c658Sreinoud mntonnamelen = strlen(mntonname);
1789e979c658Sreinoud
1790e979c658Sreinoud error = 0;
1791e979c658Sreinoud first = 1;
1792e3b6b345Sreinoud while (filesize - pathlen >= UDF_PATH_COMP_SIZE) {
1793e979c658Sreinoud len = UDF_PATH_COMP_SIZE;
1794e979c658Sreinoud memcpy(&pathcomp, pathpos, len);
1795e979c658Sreinoud l_ci = pathcomp.l_ci;
1796e979c658Sreinoud switch (pathcomp.type) {
1797e979c658Sreinoud case UDF_PATH_COMP_ROOT :
179806993e5fSreinoud /* XXX should check for l_ci; bugcompatible now */
179906993e5fSreinoud if ((targetlen < 1) || !first) {
1800e979c658Sreinoud error = EINVAL;
1801e979c658Sreinoud break;
1802e979c658Sreinoud }
1803e979c658Sreinoud *targetpos++ = '/'; targetlen--;
1804e979c658Sreinoud break;
1805e979c658Sreinoud case UDF_PATH_COMP_MOUNTROOT :
180606993e5fSreinoud /* XXX what should it be if l_ci > 0 ? [4/48.16.1.2] */
1807e979c658Sreinoud if (l_ci || (targetlen < mntonnamelen+1) || !first) {
1808e979c658Sreinoud error = EINVAL;
1809e979c658Sreinoud break;
1810e979c658Sreinoud }
1811e979c658Sreinoud memcpy(targetpos, mntonname, mntonnamelen);
1812e979c658Sreinoud targetpos += mntonnamelen; targetlen -= mntonnamelen;
1813e3b6b345Sreinoud if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) {
1814e979c658Sreinoud /* more follows, so must be directory */
1815e979c658Sreinoud *targetpos++ = '/'; targetlen--;
1816e979c658Sreinoud }
1817e979c658Sreinoud break;
1818e979c658Sreinoud case UDF_PATH_COMP_PARENTDIR :
181906993e5fSreinoud /* XXX should check for l_ci; bugcompatible now */
182006993e5fSreinoud if (targetlen < 3) {
1821e979c658Sreinoud error = EINVAL;
1822e979c658Sreinoud break;
1823e979c658Sreinoud }
1824e979c658Sreinoud *targetpos++ = '.'; targetlen--;
1825e979c658Sreinoud *targetpos++ = '.'; targetlen--;
1826e979c658Sreinoud *targetpos++ = '/'; targetlen--;
1827e979c658Sreinoud break;
1828e979c658Sreinoud case UDF_PATH_COMP_CURDIR :
182906993e5fSreinoud /* XXX should check for l_ci; bugcompatible now */
183006993e5fSreinoud if (targetlen < 2) {
1831e979c658Sreinoud error = EINVAL;
1832e979c658Sreinoud break;
1833e979c658Sreinoud }
1834e979c658Sreinoud *targetpos++ = '.'; targetlen--;
1835e979c658Sreinoud *targetpos++ = '/'; targetlen--;
1836e979c658Sreinoud break;
1837e979c658Sreinoud case UDF_PATH_COMP_NAME :
1838dc6314f8Sreinoud if (l_ci == 0) {
1839dc6314f8Sreinoud error = EINVAL;
1840dc6314f8Sreinoud break;
1841dc6314f8Sreinoud }
1842e979c658Sreinoud memset(tmpname, 0, PATH_MAX);
1843e979c658Sreinoud memcpy(&pathcomp, pathpos, len + l_ci);
18448902baa6Sreinoud udf_to_unix_name(tmpname, MAXPATHLEN,
18458902baa6Sreinoud pathcomp.ident, l_ci,
1846e979c658Sreinoud &udf_node->ump->logical_vol->desc_charset);
1847e979c658Sreinoud namelen = strlen(tmpname);
1848e979c658Sreinoud if (targetlen < namelen + 1) {
1849e979c658Sreinoud error = EINVAL;
1850e979c658Sreinoud break;
1851e979c658Sreinoud }
1852e979c658Sreinoud memcpy(targetpos, tmpname, namelen);
1853e979c658Sreinoud targetpos += namelen; targetlen -= namelen;
1854e3b6b345Sreinoud if (filesize-pathlen > UDF_PATH_COMP_SIZE+l_ci) {
1855e979c658Sreinoud /* more follows, so must be directory */
1856e979c658Sreinoud *targetpos++ = '/'; targetlen--;
1857e979c658Sreinoud }
1858e979c658Sreinoud break;
1859e979c658Sreinoud default :
1860e979c658Sreinoud error = EINVAL;
1861e979c658Sreinoud break;
1862e979c658Sreinoud }
1863e979c658Sreinoud first = 0;
1864e979c658Sreinoud if (error)
1865e979c658Sreinoud break;
1866e979c658Sreinoud pathpos += UDF_PATH_COMP_SIZE + l_ci;
1867e979c658Sreinoud pathlen += UDF_PATH_COMP_SIZE + l_ci;
1868e979c658Sreinoud
1869e979c658Sreinoud }
1870e979c658Sreinoud /* all processed? */
1871e3b6b345Sreinoud if (filesize - pathlen > 0)
1872e979c658Sreinoud error = EINVAL;
1873e979c658Sreinoud
1874e3b6b345Sreinoud free(pathbuf, M_UDFTEMP);
1875e3b6b345Sreinoud free(tmpname, M_UDFTEMP);
1876e3b6b345Sreinoud
1877e3b6b345Sreinoud *length = PATH_MAX - targetlen;
1878e3b6b345Sreinoud return error;
1879e3b6b345Sreinoud }
1880e3b6b345Sreinoud
1881e3b6b345Sreinoud
1882e3b6b345Sreinoud int
udf_readlink(void * v)1883e3b6b345Sreinoud udf_readlink(void *v)
1884e3b6b345Sreinoud {
1885e3b6b345Sreinoud struct vop_readlink_args /* {
1886e3b6b345Sreinoud struct vnode *a_vp;
1887e3b6b345Sreinoud struct uio *a_uio;
1888e3b6b345Sreinoud kauth_cred_t a_cred;
1889e3b6b345Sreinoud } */ *ap = v;
1890e3b6b345Sreinoud struct vnode *vp = ap->a_vp;
1891e3b6b345Sreinoud struct udf_node *udf_node = VTOI(vp);
1892e3b6b345Sreinoud struct file_entry *fe = udf_node->fe;
1893e3b6b345Sreinoud struct extfile_entry *efe = udf_node->efe;
1894e3b6b345Sreinoud struct uio *uio = ap->a_uio;
1895e3b6b345Sreinoud uint64_t filesize;
1896e3b6b345Sreinoud uint8_t *targetbuf;
1897e3b6b345Sreinoud int length;
1898e3b6b345Sreinoud int error;
1899e3b6b345Sreinoud
1900e3b6b345Sreinoud DPRINTF(CALL, ("udf_readlink called\n"));
1901e3b6b345Sreinoud
1902e3b6b345Sreinoud if (fe) {
1903e3b6b345Sreinoud filesize = udf_rw64(fe->inf_len);
1904e3b6b345Sreinoud } else {
1905e3b6b345Sreinoud assert(udf_node->efe);
1906e3b6b345Sreinoud filesize = udf_rw64(efe->inf_len);
1907e3b6b345Sreinoud }
1908e3b6b345Sreinoud
1909e3b6b345Sreinoud /* claim temporary buffers for translation */
1910e3b6b345Sreinoud targetbuf = malloc(PATH_MAX+1, M_UDFTEMP, M_WAITOK);
1911e3b6b345Sreinoud
1912e3b6b345Sreinoud error = udf_do_readlink(udf_node, filesize, targetbuf, &length);
1913e3b6b345Sreinoud
1914e979c658Sreinoud /* uiomove() to destination */
1915e979c658Sreinoud if (!error)
1916e3b6b345Sreinoud uiomove(targetbuf, length, uio);
1917e979c658Sreinoud
1918e979c658Sreinoud free(targetbuf, M_UDFTEMP);
1919e979c658Sreinoud return error;
1920cff5e7adSreinoud }
1921cff5e7adSreinoud
1922cff5e7adSreinoud /* --------------------------------------------------------------------- */
1923cff5e7adSreinoud
19245e29d122Sreinoud /*
1925a7795a09Sreinoud * udf_rename() moved to udf_rename.c
19265e29d122Sreinoud */
19275e29d122Sreinoud
1928cff5e7adSreinoud /* --------------------------------------------------------------------- */
1929cff5e7adSreinoud
1930cff5e7adSreinoud int
udf_remove(void * v)1931e979c658Sreinoud udf_remove(void *v)
1932cff5e7adSreinoud {
1933982ae832Sthorpej struct vop_remove_v3_args /* {
1934cff5e7adSreinoud struct vnode *a_dvp;
1935e979c658Sreinoud struct vnode *a_vp;
1936cff5e7adSreinoud struct componentname *a_cnp;
1937982ae832Sthorpej nlink_t ctx_vp_new_nlink;
1938cff5e7adSreinoud } */ *ap = v;
1939cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
1940e979c658Sreinoud struct vnode *vp = ap->a_vp;
1941cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
1942982581e0Smbalmer struct udf_node *dir_node = VTOI(dvp);
1943e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1944e979c658Sreinoud struct udf_mount *ump = dir_node->ump;
1945e979c658Sreinoud int error;
1946cff5e7adSreinoud
1947e979c658Sreinoud DPRINTF(CALL, ("udf_remove called\n"));
1948e979c658Sreinoud if (vp->v_type != VDIR) {
1949e979c658Sreinoud error = udf_dir_detach(ump, dir_node, udf_node, cnp);
1950e979c658Sreinoud DPRINTFIF(NODE, error, ("\tgot error removing file\n"));
1951982ae832Sthorpej if (error == 0) {
1952982ae832Sthorpej if (udf_node->fe) {
1953982ae832Sthorpej ap->ctx_vp_new_nlink =
1954982ae832Sthorpej udf_rw16(udf_node->fe->link_cnt);
1955982ae832Sthorpej } else {
1956982ae832Sthorpej KASSERT(udf_node->efe != NULL);
1957982ae832Sthorpej ap->ctx_vp_new_nlink =
1958982ae832Sthorpej udf_rw16(udf_node->efe->link_cnt);
1959982ae832Sthorpej }
1960982ae832Sthorpej }
1961e979c658Sreinoud } else {
1962e979c658Sreinoud DPRINTF(NODE, ("\tis a directory: perm. denied\n"));
1963e979c658Sreinoud error = EPERM;
1964e979c658Sreinoud }
1965cff5e7adSreinoud
1966e979c658Sreinoud if (dvp == vp)
1967e979c658Sreinoud vrele(vp);
1968e979c658Sreinoud else
1969e979c658Sreinoud vput(vp);
1970cff5e7adSreinoud
1971e979c658Sreinoud return error;
1972cff5e7adSreinoud }
1973cff5e7adSreinoud
1974cff5e7adSreinoud /* --------------------------------------------------------------------- */
1975cff5e7adSreinoud
1976cff5e7adSreinoud int
udf_rmdir(void * v)1977cff5e7adSreinoud udf_rmdir(void *v)
1978cff5e7adSreinoud {
19796fa7b158Sriastradh struct vop_rmdir_v2_args /* {
1980cff5e7adSreinoud struct vnode *a_dvp;
1981cff5e7adSreinoud struct vnode *a_vp;
1982cff5e7adSreinoud struct componentname *a_cnp;
1983cff5e7adSreinoud } */ *ap = v;
1984cff5e7adSreinoud struct vnode *vp = ap->a_vp;
1985cff5e7adSreinoud struct vnode *dvp = ap->a_dvp;
1986cff5e7adSreinoud struct componentname *cnp = ap->a_cnp;
1987982581e0Smbalmer struct udf_node *dir_node = VTOI(dvp);
1988e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
1989e979c658Sreinoud struct udf_mount *ump = dir_node->ump;
1990eb513d51Sreinoud int error, isempty;
1991cff5e7adSreinoud
1992b3745214Sreinoud DPRINTF(CALL, ("udf_rmdir '%s' called\n", cnp->cn_nameptr));
1993cff5e7adSreinoud
1994e979c658Sreinoud /* don't allow '.' to be deleted */
1995e979c658Sreinoud if (dir_node == udf_node) {
19966fa7b158Sriastradh vrele(vp);
1997e979c658Sreinoud return EINVAL;
1998e979c658Sreinoud }
1999e979c658Sreinoud
2000eb513d51Sreinoud /* make sure our `leaf' node's hash is populated */
2001eb513d51Sreinoud dirhash_get(&udf_node->dir_hash);
2002eb513d51Sreinoud error = udf_dirhash_fill(udf_node);
2003eb513d51Sreinoud if (error) {
2004eb513d51Sreinoud dirhash_put(udf_node->dir_hash);
2005eb513d51Sreinoud return error;
2006e979c658Sreinoud }
2007eb513d51Sreinoud
2008eb513d51Sreinoud /* check to see if the directory is empty */
2009eb513d51Sreinoud isempty = dirhash_dir_isempty(udf_node->dir_hash);
2010eb513d51Sreinoud dirhash_put(udf_node->dir_hash);
2011eb513d51Sreinoud
2012eb513d51Sreinoud if (!isempty) {
2013cff5e7adSreinoud vput(vp);
2014e979c658Sreinoud return ENOTEMPTY;
2015cff5e7adSreinoud }
2016cff5e7adSreinoud
2017ab09c24fSreinoud /* detach the node from the directory, udf_node is an empty dir here */
2018e979c658Sreinoud error = udf_dir_detach(ump, dir_node, udf_node, cnp);
2019e979c658Sreinoud if (error == 0) {
2020e979c658Sreinoud cache_purge(vp);
2021e979c658Sreinoud // cache_purge(dvp); /* XXX from msdosfs, why? */
2022ab09c24fSreinoud /*
2023ab09c24fSreinoud * Bug alert: we need to remove '..' from the detaching
2024ab09c24fSreinoud * udf_node so further lookups of this are not possible. This
2025ab09c24fSreinoud * prevents a process in a deleted directory from going to its
202609fb1792Sandvar * deleted parent. Since `udf_node' is guaranteed to be empty
2027ab09c24fSreinoud * here, trunc it so no fids are there.
2028ab09c24fSreinoud */
2029ab09c24fSreinoud dirhash_purge(&udf_node->dir_hash);
2030ab09c24fSreinoud udf_shrink_node(udf_node, 0);
2031e979c658Sreinoud }
2032e6b5374eSreinoud DPRINTFIF(NODE, error, ("\tgot error removing dir\n"));
2033e979c658Sreinoud
20346fa7b158Sriastradh /* put the node and exit */
2035e979c658Sreinoud vput(vp);
2036e979c658Sreinoud
2037cff5e7adSreinoud return error;
2038cff5e7adSreinoud }
2039cff5e7adSreinoud
2040cff5e7adSreinoud /* --------------------------------------------------------------------- */
2041cff5e7adSreinoud
2042cff5e7adSreinoud int
udf_fsync(void * v)2043cff5e7adSreinoud udf_fsync(void *v)
2044cff5e7adSreinoud {
2045cff5e7adSreinoud struct vop_fsync_args /* {
2046cff5e7adSreinoud struct vnode *a_vp;
2047fc9422c9Selad kauth_cred_t a_cred;
2048cff5e7adSreinoud int a_flags;
2049cff5e7adSreinoud off_t offlo;
2050cff5e7adSreinoud off_t offhi;
2051cff5e7adSreinoud struct proc *a_p;
2052cff5e7adSreinoud } */ *ap = v;
2053cff5e7adSreinoud struct vnode *vp = ap->a_vp;
2054e979c658Sreinoud struct udf_node *udf_node = VTOI(vp);
2055e979c658Sreinoud int error, flags, wait;
2056cff5e7adSreinoud
205742dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync called on %p : %s, %s\n",
205842dbf4bbSreinoud udf_node,
2059e979c658Sreinoud (ap->a_flags & FSYNC_WAIT) ? "wait":"no wait",
2060e979c658Sreinoud (ap->a_flags & FSYNC_DATAONLY) ? "data_only":"complete"));
2061cff5e7adSreinoud
2062e979c658Sreinoud /* flush data and wait for it when requested */
2063e979c658Sreinoud wait = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
20648306a9edSchs error = vflushbuf(vp, ap->a_flags);
206587522af4Shannken if (error)
206687522af4Shannken return error;
2067e979c658Sreinoud
20684d5c88faSreinoud if (udf_node == NULL) {
20694d5c88faSreinoud printf("udf_fsync() called on NULL udf_node!\n");
20704d5c88faSreinoud return 0;
20714d5c88faSreinoud }
20724d5c88faSreinoud if (vp->v_tag != VT_UDF) {
20734d5c88faSreinoud printf("udf_fsync() called on node not tagged as UDF node!\n");
20744d5c88faSreinoud return 0;
20754d5c88faSreinoud }
20764d5c88faSreinoud
2077e979c658Sreinoud /* set our times */
2078e979c658Sreinoud udf_itimes(udf_node, NULL, NULL, NULL);
2079e979c658Sreinoud
2080e979c658Sreinoud /* if called when mounted readonly, never write back */
2081e979c658Sreinoud if (vp->v_mount->mnt_flag & MNT_RDONLY)
2082e979c658Sreinoud return 0;
2083e979c658Sreinoud
2084e979c658Sreinoud /* if only data is requested, return */
2085e979c658Sreinoud if (ap->a_flags & FSYNC_DATAONLY)
2086e979c658Sreinoud return 0;
2087e979c658Sreinoud
2088e979c658Sreinoud /* check if the node is dirty 'enough'*/
2089e979c658Sreinoud flags = udf_node->i_flags & (IN_MODIFIED | IN_ACCESSED);
2090e979c658Sreinoud if (flags == 0)
2091e979c658Sreinoud return 0;
2092e979c658Sreinoud
2093e979c658Sreinoud /* if we don't have to wait, check for IO pending */
2094e979c658Sreinoud if (!wait) {
2095e979c658Sreinoud if (vp->v_numoutput > 0) {
209642dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, rejecting on v_numoutput\n", udf_node));
2097e979c658Sreinoud return 0;
2098e979c658Sreinoud }
2099e979c658Sreinoud if (udf_node->outstanding_bufs > 0) {
210042dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_bufs\n", udf_node));
2101e979c658Sreinoud return 0;
2102e979c658Sreinoud }
2103e979c658Sreinoud if (udf_node->outstanding_nodedscr > 0) {
210442dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, rejecting on outstanding_nodedscr\n", udf_node));
2105e979c658Sreinoud return 0;
2106e979c658Sreinoud }
2107e979c658Sreinoud }
2108e979c658Sreinoud
2109e979c658Sreinoud /* wait until vp->v_numoutput reaches zero i.e. is finished */
2110e979c658Sreinoud if (wait) {
211142dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, waiting\n", udf_node));
2112e225b7bdSrmind mutex_enter(vp->v_interlock);
2113e979c658Sreinoud while (vp->v_numoutput) {
211442dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, v_numoutput %d\n", udf_node, vp->v_numoutput));
2115e225b7bdSrmind cv_timedwait(&vp->v_cv, vp->v_interlock, hz/8);
2116e979c658Sreinoud }
2117e225b7bdSrmind mutex_exit(vp->v_interlock);
211842dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, fin wait\n", udf_node));
2119e979c658Sreinoud }
2120e979c658Sreinoud
2121e979c658Sreinoud /* write out node and wait for it if requested */
212242dbf4bbSreinoud DPRINTF(SYNC, ("udf_fsync %p, writeout node\n", udf_node));
2123e979c658Sreinoud error = udf_writeout_node(udf_node, wait);
2124e979c658Sreinoud if (error)
2125e979c658Sreinoud return error;
2126e979c658Sreinoud
2127e979c658Sreinoud /* TODO/XXX if ap->a_flags & FSYNC_CACHE, we ought to do a disc sync */
2128cff5e7adSreinoud
2129cff5e7adSreinoud return 0;
2130cff5e7adSreinoud }
2131cff5e7adSreinoud
2132cff5e7adSreinoud /* --------------------------------------------------------------------- */
2133cff5e7adSreinoud
2134cff5e7adSreinoud int
udf_advlock(void * v)2135cff5e7adSreinoud udf_advlock(void *v)
2136cff5e7adSreinoud {
2137cff5e7adSreinoud struct vop_advlock_args /* {
2138cff5e7adSreinoud struct vnode *a_vp;
2139cff5e7adSreinoud void *a_id;
2140cff5e7adSreinoud int a_op;
2141cff5e7adSreinoud struct flock *a_fl;
2142cff5e7adSreinoud int a_flags;
2143cff5e7adSreinoud } */ *ap = v;
2144cff5e7adSreinoud struct vnode *vp = ap->a_vp;
2145cff5e7adSreinoud struct udf_node *udf_node = VTOI(vp);
2146cff5e7adSreinoud struct file_entry *fe;
2147cff5e7adSreinoud struct extfile_entry *efe;
2148cff5e7adSreinoud uint64_t file_size;
2149cff5e7adSreinoud
2150cff5e7adSreinoud DPRINTF(LOCKING, ("udf_advlock called\n"));
2151cff5e7adSreinoud
2152cff5e7adSreinoud /* get directory filesize */
2153cff5e7adSreinoud if (udf_node->fe) {
2154cff5e7adSreinoud fe = udf_node->fe;
2155cff5e7adSreinoud file_size = udf_rw64(fe->inf_len);
2156cff5e7adSreinoud } else {
2157cff5e7adSreinoud assert(udf_node->efe);
2158cff5e7adSreinoud efe = udf_node->efe;
2159cff5e7adSreinoud file_size = udf_rw64(efe->inf_len);
21600c1391f0Schristos }
2161cff5e7adSreinoud
2162cff5e7adSreinoud return lf_advlock(ap, &udf_node->lockf, file_size);
2163cff5e7adSreinoud }
2164cff5e7adSreinoud
2165cff5e7adSreinoud /* --------------------------------------------------------------------- */
2166cff5e7adSreinoud
2167cff5e7adSreinoud /* Global vfs vnode data structures for udfs */
216802cdf4d2Sdsl int (**udf_vnodeop_p)(void *);
2169cff5e7adSreinoud
2170cff5e7adSreinoud const struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
2171cff5e7adSreinoud { &vop_default_desc, vn_default_error },
2172c6c16cd0Sdholland { &vop_parsepath_desc, genfs_parsepath }, /* parsepath */
2173cff5e7adSreinoud { &vop_lookup_desc, udf_lookup }, /* lookup */
2174e979c658Sreinoud { &vop_create_desc, udf_create }, /* create */
2175cff5e7adSreinoud { &vop_mknod_desc, udf_mknod }, /* mknod */ /* TODO */
2176cff5e7adSreinoud { &vop_open_desc, udf_open }, /* open */
2177cff5e7adSreinoud { &vop_close_desc, udf_close }, /* close */
2178cff5e7adSreinoud { &vop_access_desc, udf_access }, /* access */
21799aa2a9c3Schristos { &vop_accessx_desc, genfs_accessx }, /* accessx */
2180cff5e7adSreinoud { &vop_getattr_desc, udf_getattr }, /* getattr */
2181e979c658Sreinoud { &vop_setattr_desc, udf_setattr }, /* setattr */ /* TODO chflags */
2182cff5e7adSreinoud { &vop_read_desc, udf_read }, /* read */
2183cff5e7adSreinoud { &vop_write_desc, udf_write }, /* write */ /* WRITE */
218405d075b3Sdholland { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */
218505d075b3Sdholland { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */
2186cff5e7adSreinoud { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ /* TODO? */
2187cff5e7adSreinoud { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ /* TODO? */
2188cff5e7adSreinoud { &vop_poll_desc, genfs_poll }, /* poll */ /* TODO/OK? */
2189cff5e7adSreinoud { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ /* ? */
2190cff5e7adSreinoud { &vop_revoke_desc, genfs_revoke }, /* revoke */ /* TODO? */
2191cff5e7adSreinoud { &vop_mmap_desc, genfs_mmap }, /* mmap */ /* OK? */
2192e979c658Sreinoud { &vop_fsync_desc, udf_fsync }, /* fsync */
2193cff5e7adSreinoud { &vop_seek_desc, genfs_seek }, /* seek */
2194e979c658Sreinoud { &vop_remove_desc, udf_remove }, /* remove */
2195cff5e7adSreinoud { &vop_link_desc, udf_link }, /* link */ /* TODO */
2196cff5e7adSreinoud { &vop_rename_desc, udf_rename }, /* rename */ /* TODO */
2197e979c658Sreinoud { &vop_mkdir_desc, udf_mkdir }, /* mkdir */
2198e979c658Sreinoud { &vop_rmdir_desc, udf_rmdir }, /* rmdir */
2199cff5e7adSreinoud { &vop_symlink_desc, udf_symlink }, /* symlink */ /* TODO */
2200cff5e7adSreinoud { &vop_readdir_desc, udf_readdir }, /* readdir */
2201cff5e7adSreinoud { &vop_readlink_desc, udf_readlink }, /* readlink */ /* TEST ME */
2202cff5e7adSreinoud { &vop_abortop_desc, genfs_abortop }, /* abortop */ /* TODO/OK? */
2203cff5e7adSreinoud { &vop_inactive_desc, udf_inactive }, /* inactive */
2204cff5e7adSreinoud { &vop_reclaim_desc, udf_reclaim }, /* reclaim */
2205cff5e7adSreinoud { &vop_lock_desc, genfs_lock }, /* lock */
2206cff5e7adSreinoud { &vop_unlock_desc, genfs_unlock }, /* unlock */
2207cff5e7adSreinoud { &vop_bmap_desc, udf_trivial_bmap }, /* bmap */ /* 1:1 bmap */
2208e979c658Sreinoud { &vop_strategy_desc, udf_vfsstrategy },/* strategy */
2209cff5e7adSreinoud /* { &vop_print_desc, udf_print }, */ /* print */
2210cff5e7adSreinoud { &vop_islocked_desc, genfs_islocked }, /* islocked */
2211cff5e7adSreinoud { &vop_pathconf_desc, udf_pathconf }, /* pathconf */
2212cff5e7adSreinoud { &vop_advlock_desc, udf_advlock }, /* advlock */ /* TEST ME */
2213cff5e7adSreinoud { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ /* ->strategy */
2214cff5e7adSreinoud { &vop_getpages_desc, genfs_getpages }, /* getpages */
2215cff5e7adSreinoud { &vop_putpages_desc, genfs_putpages }, /* putpages */
2216cff5e7adSreinoud { NULL, NULL }
2217cff5e7adSreinoud };
2218cff5e7adSreinoud
2219cff5e7adSreinoud
2220cff5e7adSreinoud const struct vnodeopv_desc udf_vnodeop_opv_desc = {
2221cff5e7adSreinoud &udf_vnodeop_p, udf_vnodeop_entries
2222cff5e7adSreinoud };
2223