Deleted Added
full compact
udf_vnops.c (111119) udf_vnops.c (111741)
1/*-
2 * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/fs/udf/udf_vnops.c 111119 2003-02-19 05:47:46Z imp $
26 * $FreeBSD: head/sys/fs/udf/udf_vnops.c 111741 2003-03-02 15:50:23Z des $
27 */
28
29/* udf_vnops.c */
30/* Take care of the vnode side of things */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/namei.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/stat.h>
38#include <sys/bio.h>
39#include <sys/buf.h>
40#include <sys/mount.h>
41#include <sys/vnode.h>
42#include <sys/dirent.h>
43#include <sys/queue.h>
44#include <sys/unistd.h>
45
46#include <vm/uma.h>
47
48#include <fs/udf/ecma167-udf.h>
49#include <fs/udf/osta.h>
50#include <fs/udf/udf.h>
51
52static int udf_access(struct vop_access_args *);
53static int udf_getattr(struct vop_getattr_args *);
54static int udf_ioctl(struct vop_ioctl_args *);
55static int udf_pathconf(struct vop_pathconf_args *);
56static int udf_read(struct vop_read_args *);
57static int udf_readdir(struct vop_readdir_args *);
58static int udf_readlink(struct vop_readlink_args *ap);
59static int udf_strategy(struct vop_strategy_args *);
60static int udf_print(struct vop_print_args *);
61static int udf_bmap(struct vop_bmap_args *);
62static int udf_lookup(struct vop_cachedlookup_args *);
63static int udf_reclaim(struct vop_reclaim_args *);
64static void udf_dumpblock(void *, int) __unused;
65static int udf_readatoffset(struct udf_node *, int *, int, struct buf **, uint8_t **);
66static int udf_bmap_internal(struct udf_node *, uint32_t, daddr_t *, uint32_t *);
67
68vop_t **udf_vnodeop_p;
69static struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
70 { &vop_default_desc, (vop_t *) vop_defaultop },
71 { &vop_access_desc, (vop_t *) udf_access },
72 { &vop_bmap_desc, (vop_t *) udf_bmap },
73 { &vop_cachedlookup_desc, (vop_t *) udf_lookup },
74 { &vop_getattr_desc, (vop_t *) udf_getattr },
75 { &vop_ioctl_desc, (vop_t *) udf_ioctl },
76 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
77 { &vop_pathconf_desc, (vop_t *) udf_pathconf },
78 { &vop_print_desc, (vop_t *) udf_print },
79 { &vop_read_desc, (vop_t *) udf_read },
80 { &vop_readdir_desc, (vop_t *) udf_readdir },
81 { &vop_readlink_desc, (vop_t *) udf_readlink },
82 { &vop_reclaim_desc, (vop_t *) udf_reclaim },
83 { &vop_strategy_desc, (vop_t *) udf_strategy },
84 { NULL, NULL }
85};
86static struct vnodeopv_desc udf_vnodeop_opv_desc =
87 { &udf_vnodeop_p, udf_vnodeop_entries };
88VNODEOP_SET(udf_vnodeop_opv_desc);
89
90MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
91MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
92
93#define UDF_INVALID_BMAP -1
94
95/* Look up a udf_node based on the ino_t passed in and return it's vnode */
96int
97udf_hashlookup(struct udf_mnt *udfmp, ino_t id, int flags, struct vnode **vpp)
98{
99 struct udf_node *node;
100 int error;
101
102 *vpp = NULL;
103
104loop:
105 mtx_lock(&udfmp->hash_mtx);
106 TAILQ_FOREACH(node, &udfmp->udf_tqh, tq) {
107 if (node->hash_id == id) {
108 VI_LOCK(node->i_vnode);
109 mtx_unlock(&udfmp->hash_mtx);
110 error = vget(node->i_vnode, flags | LK_INTERLOCK,
111 curthread);
112 if (error == ENOENT)
113 goto loop;
114 if (error)
115 return (error);
116 *vpp = node->i_vnode;
117 return (0);
118 }
119 }
120
121 mtx_unlock(&udfmp->hash_mtx);
122 return (0);
123}
124
125int
126udf_hashins(struct udf_node *node)
127{
128 struct udf_mnt *udfmp;
129
130 udfmp = node->udfmp;
131
132 mtx_lock(&udfmp->hash_mtx);
133 TAILQ_INSERT_TAIL(&udfmp->udf_tqh, node, tq);
134 mtx_unlock(&udfmp->hash_mtx);
135 vn_lock(node->i_vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
136
137 return (0);
138}
139
140int
141udf_hashrem(struct udf_node *node)
142{
143 struct udf_mnt *udfmp;
144
145 udfmp = node->udfmp;
146
147 mtx_lock(&udfmp->hash_mtx);
148 TAILQ_REMOVE(&udfmp->udf_tqh, node, tq);
149 mtx_unlock(&udfmp->hash_mtx);
150
151 return (0);
152}
153
154int
155udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
156{
157 int error;
158 struct vnode *vp;
159
160 error = getnewvnode("udf", mp, udf_vnodeop_p, &vp);
161 if (error) {
162 printf("udf_allocv: failed to allocate new vnode\n");
163 return (error);
164 }
165
166 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
167 *vpp = vp;
168 return (0);
169}
170
171/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
172static mode_t
173udf_permtomode(struct udf_node *node)
174{
175 uint32_t perm;
176 uint32_t flags;
177 mode_t mode;
178
179 perm = node->fentry->perm;
180 flags = node->fentry->icbtag.flags;
181
182 mode = perm & UDF_FENTRY_PERM_USER_MASK;
183 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
184 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
185 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
186 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
187 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
188
189 return (mode);
190}
191
192static int
193udf_access(struct vop_access_args *a)
194{
195 struct vnode *vp;
196 struct udf_node *node;
197 mode_t a_mode, mode;
198
199 vp = a->a_vp;
200 node = VTON(vp);
201 a_mode = a->a_mode;
202
203 if (a_mode & VWRITE) {
204 switch (vp->v_type) {
205 case VDIR:
206 case VLNK:
207 case VREG:
208 return (EROFS);
209 /* NOT REACHED */
210 default:
211 break;
212 }
213 }
214
215 mode = udf_permtomode(node);
216
217 return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
218 a_mode, a->a_cred, NULL));
219}
220
221static int mon_lens[2][12] = {
222 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
223 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
224};
225
226static int
227udf_isaleapyear(int year)
228{
229 int i;
230
231 i = (year % 4) ? 0 : 1;
232 i &= (year % 100) ? 1 : 0;
233 i |= (year % 400) ? 0 : 1;
234
235 return i;
236}
237
238/*
239 * XXX This is just a rough hack. Daylight savings isn't calculated and tv_nsec
240 * is ignored.
241 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
242 */
243static void
244udf_timetotimespec(struct timestamp *time, struct timespec *t)
245{
246 int i, lpyear, daysinyear;
247 union {
248 uint16_t u_tz_offset;
249 int16_t s_tz_offset;
250 } tz;
251
252 t->tv_nsec = 0;
253
254 /* DirectCD seems to like using bogus year values */
255 if (time->year < 1970) {
256 t->tv_sec = 0;
257 return;
258 }
259
260 /* Calculate the time and day */
261 t->tv_sec = time->second;
262 t->tv_sec += time->minute * 60;
263 t->tv_sec += time->hour * 3600;
264 t->tv_sec += time->day * 3600 * 24;
265
266 /* Calclulate the month */
267 lpyear = udf_isaleapyear(time->year);
268 for (i = 1; i < time->month; i++)
269 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
270
271 /* Speed up the calculation */
272 if (time->year > 1979)
273 t->tv_sec += 315532800;
274 if (time->year > 1989)
275 t->tv_sec += 315619200;
276 if (time->year > 1999)
277 t->tv_sec += 315532800;
278 for (i = 2000; i < time->year; i++) {
279 daysinyear = udf_isaleapyear(i) + 365 ;
280 t->tv_sec += daysinyear * 3600 * 24;
281 }
282
283 /*
284 * Calculate the time zone. The timezone is 12 bit signed 2's
285 * compliment, so we gotta do some extra magic to handle it right.
286 */
287 tz.u_tz_offset = time->type_tz;
288 tz.u_tz_offset &= 0x0fff;
289 if (tz.u_tz_offset & 0x0800)
290 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
291 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
292 t->tv_sec -= tz.s_tz_offset * 60;
293
294 return;
295}
296
297static int
298udf_getattr(struct vop_getattr_args *a)
299{
300 struct vnode *vp;
301 struct udf_node *node;
302 struct vattr *vap;
303 struct file_entry *fentry;
304 struct timespec ts;
305
306 ts.tv_sec = 0;
307
308 vp = a->a_vp;
309 vap = a->a_vap;
310 node = VTON(vp);
311 fentry = node->fentry;
312
313 vap->va_fsid = dev2udev(node->i_dev);
314 vap->va_fileid = node->hash_id;
315 vap->va_mode = udf_permtomode(node);
316 vap->va_nlink = fentry->link_cnt;
317 /*
318 * XXX The spec says that -1 is valid for uid/gid and indicates an
319 * invalid uid/gid. How should this be represented?
320 */
321 vap->va_uid = (fentry->uid == -1) ? 0 : fentry->uid;
322 vap->va_gid = (fentry->gid == -1) ? 0 : fentry->gid;
323 udf_timetotimespec(&fentry->atime, &vap->va_atime);
324 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
325 vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
326 vap->va_rdev = 0; /* XXX */
327 if (vp->v_type & VDIR) {
328 /*
329 * Directories that are recorded within their ICB will show
330 * as having 0 blocks recorded. Since tradition dictates
331 * that directories consume at least one logical block,
332 * make it appear so.
333 */
334 if (fentry->logblks_rec != 0) {
335 vap->va_size = fentry->logblks_rec * node->udfmp->bsize;
336 } else {
337 vap->va_size = node->udfmp->bsize;
338 }
339 } else {
340 vap->va_size = fentry->inf_len;
341 }
342 vap->va_flags = 0;
343 vap->va_gen = 1;
344 vap->va_blocksize = node->udfmp->bsize;
345 vap->va_bytes = fentry->inf_len;
346 vap->va_type = vp->v_type;
347 vap->va_filerev = 0; /* XXX */
348 return (0);
349}
350
351/*
352 * File specific ioctls. DeCSS candidate?
353 */
354static int
355udf_ioctl(struct vop_ioctl_args *a)
356{
357 printf("%s called\n", __FUNCTION__);
358 return (ENOTTY);
359}
360
361/*
362 * I'm not sure that this has much value in a read-only filesystem, but
363 * cd9660 has it too.
364 */
365static int
366udf_pathconf(struct vop_pathconf_args *a)
367{
368
369 switch (a->a_name) {
370 case _PC_LINK_MAX:
371 *a->a_retval = 65535;
372 return (0);
373 case _PC_NAME_MAX:
374 *a->a_retval = NAME_MAX;
375 return (0);
376 case _PC_PATH_MAX:
377 *a->a_retval = PATH_MAX;
378 return (0);
379 case _PC_NO_TRUNC:
380 *a->a_retval = 1;
381 return (0);
382 default:
383 return (EINVAL);
384 }
385}
386
387static int
388udf_read(struct vop_read_args *a)
389{
390 struct vnode *vp = a->a_vp;
391 struct uio *uio = a->a_uio;
392 struct udf_node *node = VTON(vp);
393 struct buf *bp;
394 uint8_t *data;
395 int error = 0;
396 int size, fsize, offset;
397
398 if (uio->uio_offset < 0)
399 return (EINVAL);
400
401 fsize = node->fentry->inf_len;
402
403 while (uio->uio_offset < fsize && uio->uio_resid > 0) {
404 offset = uio->uio_offset;
405 size = uio->uio_resid;
406 error = udf_readatoffset(node, &size, offset, &bp, &data);
407 if (error)
408 return (error);
27 */
28
29/* udf_vnops.c */
30/* Take care of the vnode side of things */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/namei.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/stat.h>
38#include <sys/bio.h>
39#include <sys/buf.h>
40#include <sys/mount.h>
41#include <sys/vnode.h>
42#include <sys/dirent.h>
43#include <sys/queue.h>
44#include <sys/unistd.h>
45
46#include <vm/uma.h>
47
48#include <fs/udf/ecma167-udf.h>
49#include <fs/udf/osta.h>
50#include <fs/udf/udf.h>
51
52static int udf_access(struct vop_access_args *);
53static int udf_getattr(struct vop_getattr_args *);
54static int udf_ioctl(struct vop_ioctl_args *);
55static int udf_pathconf(struct vop_pathconf_args *);
56static int udf_read(struct vop_read_args *);
57static int udf_readdir(struct vop_readdir_args *);
58static int udf_readlink(struct vop_readlink_args *ap);
59static int udf_strategy(struct vop_strategy_args *);
60static int udf_print(struct vop_print_args *);
61static int udf_bmap(struct vop_bmap_args *);
62static int udf_lookup(struct vop_cachedlookup_args *);
63static int udf_reclaim(struct vop_reclaim_args *);
64static void udf_dumpblock(void *, int) __unused;
65static int udf_readatoffset(struct udf_node *, int *, int, struct buf **, uint8_t **);
66static int udf_bmap_internal(struct udf_node *, uint32_t, daddr_t *, uint32_t *);
67
68vop_t **udf_vnodeop_p;
69static struct vnodeopv_entry_desc udf_vnodeop_entries[] = {
70 { &vop_default_desc, (vop_t *) vop_defaultop },
71 { &vop_access_desc, (vop_t *) udf_access },
72 { &vop_bmap_desc, (vop_t *) udf_bmap },
73 { &vop_cachedlookup_desc, (vop_t *) udf_lookup },
74 { &vop_getattr_desc, (vop_t *) udf_getattr },
75 { &vop_ioctl_desc, (vop_t *) udf_ioctl },
76 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
77 { &vop_pathconf_desc, (vop_t *) udf_pathconf },
78 { &vop_print_desc, (vop_t *) udf_print },
79 { &vop_read_desc, (vop_t *) udf_read },
80 { &vop_readdir_desc, (vop_t *) udf_readdir },
81 { &vop_readlink_desc, (vop_t *) udf_readlink },
82 { &vop_reclaim_desc, (vop_t *) udf_reclaim },
83 { &vop_strategy_desc, (vop_t *) udf_strategy },
84 { NULL, NULL }
85};
86static struct vnodeopv_desc udf_vnodeop_opv_desc =
87 { &udf_vnodeop_p, udf_vnodeop_entries };
88VNODEOP_SET(udf_vnodeop_opv_desc);
89
90MALLOC_DEFINE(M_UDFFID, "UDF FID", "UDF FileId structure");
91MALLOC_DEFINE(M_UDFDS, "UDF DS", "UDF Dirstream structure");
92
93#define UDF_INVALID_BMAP -1
94
95/* Look up a udf_node based on the ino_t passed in and return it's vnode */
96int
97udf_hashlookup(struct udf_mnt *udfmp, ino_t id, int flags, struct vnode **vpp)
98{
99 struct udf_node *node;
100 int error;
101
102 *vpp = NULL;
103
104loop:
105 mtx_lock(&udfmp->hash_mtx);
106 TAILQ_FOREACH(node, &udfmp->udf_tqh, tq) {
107 if (node->hash_id == id) {
108 VI_LOCK(node->i_vnode);
109 mtx_unlock(&udfmp->hash_mtx);
110 error = vget(node->i_vnode, flags | LK_INTERLOCK,
111 curthread);
112 if (error == ENOENT)
113 goto loop;
114 if (error)
115 return (error);
116 *vpp = node->i_vnode;
117 return (0);
118 }
119 }
120
121 mtx_unlock(&udfmp->hash_mtx);
122 return (0);
123}
124
125int
126udf_hashins(struct udf_node *node)
127{
128 struct udf_mnt *udfmp;
129
130 udfmp = node->udfmp;
131
132 mtx_lock(&udfmp->hash_mtx);
133 TAILQ_INSERT_TAIL(&udfmp->udf_tqh, node, tq);
134 mtx_unlock(&udfmp->hash_mtx);
135 vn_lock(node->i_vnode, LK_EXCLUSIVE | LK_RETRY, curthread);
136
137 return (0);
138}
139
140int
141udf_hashrem(struct udf_node *node)
142{
143 struct udf_mnt *udfmp;
144
145 udfmp = node->udfmp;
146
147 mtx_lock(&udfmp->hash_mtx);
148 TAILQ_REMOVE(&udfmp->udf_tqh, node, tq);
149 mtx_unlock(&udfmp->hash_mtx);
150
151 return (0);
152}
153
154int
155udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
156{
157 int error;
158 struct vnode *vp;
159
160 error = getnewvnode("udf", mp, udf_vnodeop_p, &vp);
161 if (error) {
162 printf("udf_allocv: failed to allocate new vnode\n");
163 return (error);
164 }
165
166 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
167 *vpp = vp;
168 return (0);
169}
170
171/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
172static mode_t
173udf_permtomode(struct udf_node *node)
174{
175 uint32_t perm;
176 uint32_t flags;
177 mode_t mode;
178
179 perm = node->fentry->perm;
180 flags = node->fentry->icbtag.flags;
181
182 mode = perm & UDF_FENTRY_PERM_USER_MASK;
183 mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
184 mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
185 mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
186 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
187 mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
188
189 return (mode);
190}
191
192static int
193udf_access(struct vop_access_args *a)
194{
195 struct vnode *vp;
196 struct udf_node *node;
197 mode_t a_mode, mode;
198
199 vp = a->a_vp;
200 node = VTON(vp);
201 a_mode = a->a_mode;
202
203 if (a_mode & VWRITE) {
204 switch (vp->v_type) {
205 case VDIR:
206 case VLNK:
207 case VREG:
208 return (EROFS);
209 /* NOT REACHED */
210 default:
211 break;
212 }
213 }
214
215 mode = udf_permtomode(node);
216
217 return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
218 a_mode, a->a_cred, NULL));
219}
220
221static int mon_lens[2][12] = {
222 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
223 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
224};
225
226static int
227udf_isaleapyear(int year)
228{
229 int i;
230
231 i = (year % 4) ? 0 : 1;
232 i &= (year % 100) ? 1 : 0;
233 i |= (year % 400) ? 0 : 1;
234
235 return i;
236}
237
238/*
239 * XXX This is just a rough hack. Daylight savings isn't calculated and tv_nsec
240 * is ignored.
241 * Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
242 */
243static void
244udf_timetotimespec(struct timestamp *time, struct timespec *t)
245{
246 int i, lpyear, daysinyear;
247 union {
248 uint16_t u_tz_offset;
249 int16_t s_tz_offset;
250 } tz;
251
252 t->tv_nsec = 0;
253
254 /* DirectCD seems to like using bogus year values */
255 if (time->year < 1970) {
256 t->tv_sec = 0;
257 return;
258 }
259
260 /* Calculate the time and day */
261 t->tv_sec = time->second;
262 t->tv_sec += time->minute * 60;
263 t->tv_sec += time->hour * 3600;
264 t->tv_sec += time->day * 3600 * 24;
265
266 /* Calclulate the month */
267 lpyear = udf_isaleapyear(time->year);
268 for (i = 1; i < time->month; i++)
269 t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
270
271 /* Speed up the calculation */
272 if (time->year > 1979)
273 t->tv_sec += 315532800;
274 if (time->year > 1989)
275 t->tv_sec += 315619200;
276 if (time->year > 1999)
277 t->tv_sec += 315532800;
278 for (i = 2000; i < time->year; i++) {
279 daysinyear = udf_isaleapyear(i) + 365 ;
280 t->tv_sec += daysinyear * 3600 * 24;
281 }
282
283 /*
284 * Calculate the time zone. The timezone is 12 bit signed 2's
285 * compliment, so we gotta do some extra magic to handle it right.
286 */
287 tz.u_tz_offset = time->type_tz;
288 tz.u_tz_offset &= 0x0fff;
289 if (tz.u_tz_offset & 0x0800)
290 tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
291 if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
292 t->tv_sec -= tz.s_tz_offset * 60;
293
294 return;
295}
296
297static int
298udf_getattr(struct vop_getattr_args *a)
299{
300 struct vnode *vp;
301 struct udf_node *node;
302 struct vattr *vap;
303 struct file_entry *fentry;
304 struct timespec ts;
305
306 ts.tv_sec = 0;
307
308 vp = a->a_vp;
309 vap = a->a_vap;
310 node = VTON(vp);
311 fentry = node->fentry;
312
313 vap->va_fsid = dev2udev(node->i_dev);
314 vap->va_fileid = node->hash_id;
315 vap->va_mode = udf_permtomode(node);
316 vap->va_nlink = fentry->link_cnt;
317 /*
318 * XXX The spec says that -1 is valid for uid/gid and indicates an
319 * invalid uid/gid. How should this be represented?
320 */
321 vap->va_uid = (fentry->uid == -1) ? 0 : fentry->uid;
322 vap->va_gid = (fentry->gid == -1) ? 0 : fentry->gid;
323 udf_timetotimespec(&fentry->atime, &vap->va_atime);
324 udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
325 vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
326 vap->va_rdev = 0; /* XXX */
327 if (vp->v_type & VDIR) {
328 /*
329 * Directories that are recorded within their ICB will show
330 * as having 0 blocks recorded. Since tradition dictates
331 * that directories consume at least one logical block,
332 * make it appear so.
333 */
334 if (fentry->logblks_rec != 0) {
335 vap->va_size = fentry->logblks_rec * node->udfmp->bsize;
336 } else {
337 vap->va_size = node->udfmp->bsize;
338 }
339 } else {
340 vap->va_size = fentry->inf_len;
341 }
342 vap->va_flags = 0;
343 vap->va_gen = 1;
344 vap->va_blocksize = node->udfmp->bsize;
345 vap->va_bytes = fentry->inf_len;
346 vap->va_type = vp->v_type;
347 vap->va_filerev = 0; /* XXX */
348 return (0);
349}
350
351/*
352 * File specific ioctls. DeCSS candidate?
353 */
354static int
355udf_ioctl(struct vop_ioctl_args *a)
356{
357 printf("%s called\n", __FUNCTION__);
358 return (ENOTTY);
359}
360
361/*
362 * I'm not sure that this has much value in a read-only filesystem, but
363 * cd9660 has it too.
364 */
365static int
366udf_pathconf(struct vop_pathconf_args *a)
367{
368
369 switch (a->a_name) {
370 case _PC_LINK_MAX:
371 *a->a_retval = 65535;
372 return (0);
373 case _PC_NAME_MAX:
374 *a->a_retval = NAME_MAX;
375 return (0);
376 case _PC_PATH_MAX:
377 *a->a_retval = PATH_MAX;
378 return (0);
379 case _PC_NO_TRUNC:
380 *a->a_retval = 1;
381 return (0);
382 default:
383 return (EINVAL);
384 }
385}
386
387static int
388udf_read(struct vop_read_args *a)
389{
390 struct vnode *vp = a->a_vp;
391 struct uio *uio = a->a_uio;
392 struct udf_node *node = VTON(vp);
393 struct buf *bp;
394 uint8_t *data;
395 int error = 0;
396 int size, fsize, offset;
397
398 if (uio->uio_offset < 0)
399 return (EINVAL);
400
401 fsize = node->fentry->inf_len;
402
403 while (uio->uio_offset < fsize && uio->uio_resid > 0) {
404 offset = uio->uio_offset;
405 size = uio->uio_resid;
406 error = udf_readatoffset(node, &size, offset, &bp, &data);
407 if (error)
408 return (error);
409 error = uiomove((caddr_t)data, size, uio);
409 error = uiomove(data, size, uio);
410 if (bp != NULL)
411 brelse(bp);
412 if (error)
413 break;
414 };
415
416 return (error);
417}
418
419/* Convienience routine to dump a block in hex */
420static void
421udf_dumpblock(void *data, int len)
422{
423 int i, j;
424
425 for (i = 0; i < len; i++) {
426 printf("\noffset= %d: ", i);
427 for (j = 0; j < 8; j++) {
428 if (i + j == len)
429 break;
430 printf("0x%02x ", (uint8_t)((uint8_t*)(data))[i + j]);
431 }
432 i += j - 1;
433 }
434 printf("\n");
435}
436
437/*
438 * Call the OSTA routines to translate the name from a CS0 dstring to a
439 * 16-bit Unicode String. Hooks need to be placed in here to translate from
440 * Unicode to the encoding that the kernel/user expects. For now, compact
441 * the encoding to 8 bits if possible. Return the length of the translated
442 * string.
443 * XXX This horribly pessimizes the 8bit case
444 */
445static int
446udf_transname(char *cs0string, char *destname, int len)
447{
448 unicode_t *transname;
449 int i, unilen = 0;
450
451 /* allocate a buffer big enough to hold an 8->16 bit expansion */
452 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
453
454 if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) {
455 printf("udf: Unicode translation failed\n");
456 uma_zfree(udf_zone_trans, transname);
457 return 0;
458 }
459
460 /* At this point, the name is in 16-bit Unicode. Compact it down
461 * to 8-bit
462 */
463 for (i = 0; i < unilen ; i++) {
464 if (transname[i] & 0xff00) {
465 destname[i] = '.'; /* Fudge the 16bit chars */
466 } else {
467 destname[i] = transname[i] & 0xff;
468 }
469 }
470
471 destname[unilen] = 0;
472 uma_zfree(udf_zone_trans, transname);
473
474 return unilen;
475}
476
477/*
478 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
479 * 0 on a successful match, nonzero therwise. Unicode work may need to be done
480 * here also.
481 */
482static int
483udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen)
484{
485 char *transname;
486 int error = 0;
487
488 /* This is overkill, but not worth creating a new zone */
489 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
490
491 cs0len = udf_transname(cs0string, transname, cs0len);
492
493 /* Easy check. If they aren't the same length, they aren't equal */
494 if ((cs0len == 0) || (cs0len != cmplen))
495 error = -1;
496 else
497 error = bcmp(transname, cmpname, cmplen);
498
499 uma_zfree(udf_zone_trans, transname);
500 return (error);
501}
502
503struct udf_uiodir {
504 struct dirent *dirent;
505 u_long *cookies;
506 int ncookies;
507 int acookies;
508 int eofflag;
509};
510
511static int
512udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
513{
514 if (uiodir->cookies != NULL) {
515 if (++uiodir->acookies > uiodir->ncookies) {
516 uiodir->eofflag = 0;
517 return (-1);
518 }
519 *uiodir->cookies++ = cookie;
520 }
521
522 if (uio->uio_resid < de_size) {
523 uiodir->eofflag = 0;
524 return (-1);
525 }
526
410 if (bp != NULL)
411 brelse(bp);
412 if (error)
413 break;
414 };
415
416 return (error);
417}
418
419/* Convienience routine to dump a block in hex */
420static void
421udf_dumpblock(void *data, int len)
422{
423 int i, j;
424
425 for (i = 0; i < len; i++) {
426 printf("\noffset= %d: ", i);
427 for (j = 0; j < 8; j++) {
428 if (i + j == len)
429 break;
430 printf("0x%02x ", (uint8_t)((uint8_t*)(data))[i + j]);
431 }
432 i += j - 1;
433 }
434 printf("\n");
435}
436
437/*
438 * Call the OSTA routines to translate the name from a CS0 dstring to a
439 * 16-bit Unicode String. Hooks need to be placed in here to translate from
440 * Unicode to the encoding that the kernel/user expects. For now, compact
441 * the encoding to 8 bits if possible. Return the length of the translated
442 * string.
443 * XXX This horribly pessimizes the 8bit case
444 */
445static int
446udf_transname(char *cs0string, char *destname, int len)
447{
448 unicode_t *transname;
449 int i, unilen = 0;
450
451 /* allocate a buffer big enough to hold an 8->16 bit expansion */
452 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
453
454 if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) {
455 printf("udf: Unicode translation failed\n");
456 uma_zfree(udf_zone_trans, transname);
457 return 0;
458 }
459
460 /* At this point, the name is in 16-bit Unicode. Compact it down
461 * to 8-bit
462 */
463 for (i = 0; i < unilen ; i++) {
464 if (transname[i] & 0xff00) {
465 destname[i] = '.'; /* Fudge the 16bit chars */
466 } else {
467 destname[i] = transname[i] & 0xff;
468 }
469 }
470
471 destname[unilen] = 0;
472 uma_zfree(udf_zone_trans, transname);
473
474 return unilen;
475}
476
477/*
478 * Compare a CS0 dstring with a name passed in from the VFS layer. Return
479 * 0 on a successful match, nonzero therwise. Unicode work may need to be done
480 * here also.
481 */
482static int
483udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen)
484{
485 char *transname;
486 int error = 0;
487
488 /* This is overkill, but not worth creating a new zone */
489 transname = uma_zalloc(udf_zone_trans, M_WAITOK);
490
491 cs0len = udf_transname(cs0string, transname, cs0len);
492
493 /* Easy check. If they aren't the same length, they aren't equal */
494 if ((cs0len == 0) || (cs0len != cmplen))
495 error = -1;
496 else
497 error = bcmp(transname, cmpname, cmplen);
498
499 uma_zfree(udf_zone_trans, transname);
500 return (error);
501}
502
503struct udf_uiodir {
504 struct dirent *dirent;
505 u_long *cookies;
506 int ncookies;
507 int acookies;
508 int eofflag;
509};
510
511static int
512udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
513{
514 if (uiodir->cookies != NULL) {
515 if (++uiodir->acookies > uiodir->ncookies) {
516 uiodir->eofflag = 0;
517 return (-1);
518 }
519 *uiodir->cookies++ = cookie;
520 }
521
522 if (uio->uio_resid < de_size) {
523 uiodir->eofflag = 0;
524 return (-1);
525 }
526
527 return (uiomove((caddr_t)uiodir->dirent, de_size, uio));
527 return (uiomove(uiodir->dirent, de_size, uio));
528}
529
530static struct udf_dirstream *
531udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
532{
533 struct udf_dirstream *ds;
534
535 ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
536
537 ds->node = node;
538 ds->offset = offset;
539 ds->udfmp = udfmp;
540 ds->fsize = fsize;
541
542 return (ds);
543}
544
545static struct fileid_desc *
546udf_getfid(struct udf_dirstream *ds)
547{
548 struct fileid_desc *fid;
549 int error, frag_size = 0, total_fid_size;
550
551 /* End of directory? */
552 if (ds->offset + ds->off >= ds->fsize) {
553 ds->error = 0;
554 return (NULL);
555 }
556
557 /* Grab the first extent of the directory */
558 if (ds->off == 0) {
559 ds->size = 0;
560 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
561 &ds->bp, &ds->data);
562 if (error) {
563 ds->error = error;
564 return (NULL);
565 }
566 }
567
568 /*
569 * Clean up from a previous fragmented FID.
570 * XXX Is this the right place for this?
571 */
572 if (ds->fid_fragment && ds->buf != NULL) {
573 ds->fid_fragment = 0;
574 FREE(ds->buf, M_UDFFID);
575 }
576
577 fid = (struct fileid_desc*)&ds->data[ds->off];
578
579 /*
580 * Check to see if the fid is fragmented. The first test
581 * ensures that we don't wander off the end of the buffer
582 * looking for the l_iu and l_fi fields.
583 */
584 if (ds->off + UDF_FID_SIZE > ds->size ||
585 ds->off + fid->l_iu + fid->l_fi + UDF_FID_SIZE > ds->size) {
586
587 /* Copy what we have of the fid into a buffer */
588 frag_size = ds->size - ds->off;
589 if (frag_size >= ds->udfmp->bsize) {
590 printf("udf: invalid FID fragment\n");
591 ds->error = EINVAL;
592 return (NULL);
593 }
594
595 /*
596 * File ID descriptors can only be at most one
597 * logical sector in size.
598 */
599 MALLOC(ds->buf, uint8_t*, ds->udfmp->bsize, M_UDFFID,
600 M_WAITOK | M_ZERO);
601 bcopy(fid, ds->buf, frag_size);
602
603 /* Reduce all of the casting magic */
604 fid = (struct fileid_desc*)ds->buf;
605
606 if (ds->bp != NULL)
607 brelse(ds->bp);
608
609 /* Fetch the next allocation */
610 ds->offset += ds->size;
611 ds->size = 0;
612 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
613 &ds->bp, &ds->data);
614 if (error) {
615 ds->error = error;
616 return (NULL);
617 }
618
619 /*
620 * If the fragment was so small that we didn't get
621 * the l_iu and l_fi fields, copy those in.
622 */
623 if (frag_size < UDF_FID_SIZE)
624 bcopy(ds->data, &ds->buf[frag_size],
625 UDF_FID_SIZE - frag_size);
626
627 /*
628 * Now that we have enough of the fid to work with,
629 * copy in the rest of the fid from the new
630 * allocation.
631 */
632 total_fid_size = UDF_FID_SIZE + fid->l_iu + fid->l_fi;
633 if (total_fid_size > ds->udfmp->bsize) {
634 printf("udf: invalid FID\n");
635 ds->error = EIO;
636 return (NULL);
637 }
638 bcopy(ds->data, &ds->buf[frag_size],
639 total_fid_size - frag_size);
640
641 ds->fid_fragment = 1;
642 } else {
643 total_fid_size = fid->l_iu + fid->l_fi + UDF_FID_SIZE;
644 }
645
646 /*
647 * Update the offset. Align on a 4 byte boundary because the
648 * UDF spec says so.
649 */
650 ds->this_off = ds->off;
651 if (!ds->fid_fragment) {
652 ds->off += (total_fid_size + 3) & ~0x03;
653 } else {
654 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
655 }
656
657 return (fid);
658}
659
660static void
661udf_closedir(struct udf_dirstream *ds)
662{
663
664 if (ds->bp != NULL)
665 brelse(ds->bp);
666
667 if (ds->fid_fragment && ds->buf != NULL)
668 FREE(ds->buf, M_UDFFID);
669
670 uma_zfree(udf_zone_ds, ds);
671}
672
673static int
674udf_readdir(struct vop_readdir_args *a)
675{
676 struct vnode *vp;
677 struct uio *uio;
678 struct dirent dir;
679 struct udf_node *node;
680 struct fileid_desc *fid;
681 struct udf_uiodir uiodir;
682 struct udf_dirstream *ds;
683 u_long *cookies = NULL;
684 int ncookies;
685 int error = 0;
686
687 vp = a->a_vp;
688 uio = a->a_uio;
689 node = VTON(vp);
690 uiodir.eofflag = 1;
691
692 if (a->a_ncookies != NULL) {
693 /*
694 * Guess how many entries are needed. If we run out, this
695 * function will be called again and thing will pick up were
696 * it left off.
697 */
698 ncookies = uio->uio_resid / 8;
699 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
700 M_TEMP, M_WAITOK);
701 if (cookies == NULL)
702 return (ENOMEM);
703 uiodir.ncookies = ncookies;
704 uiodir.cookies = cookies;
705 uiodir.acookies = 0;
706 } else {
707 uiodir.cookies = NULL;
708 }
709
710 /*
711 * Iterate through the file id descriptors. Give the parent dir
712 * entry special attention.
713 */
714 ds = udf_opendir(node, uio->uio_offset, node->fentry->inf_len,
715 node->udfmp);
716
717 while ((fid = udf_getfid(ds)) != NULL) {
718
719 /* XXX Should we return an error on a bad fid? */
720 if (udf_checktag(&fid->tag, TAGID_FID)) {
721 printf("Invalid FID tag\n");
722 udf_dumpblock(fid, UDF_FID_SIZE);
723 error = EIO;
724 break;
725 }
726
727 /* Is this a deleted file? */
728 if (fid->file_char & UDF_FILE_CHAR_DEL)
729 continue;
730
731 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
732 /* Do up the '.' and '..' entries. Dummy values are
733 * used for the cookies since the offset here is
734 * usually zero, and NFS doesn't like that value
735 */
736 dir.d_fileno = node->hash_id;
737 dir.d_type = DT_DIR;
738 dir.d_name[0] = '.';
739 dir.d_namlen = 1;
740 dir.d_reclen = GENERIC_DIRSIZ(&dir);
741 uiodir.dirent = &dir;
742 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
743 if (error)
744 break;
745
746 dir.d_fileno = udf_getid(&fid->icb);
747 dir.d_type = DT_DIR;
748 dir.d_name[0] = '.';
749 dir.d_name[1] = '.';
750 dir.d_namlen = 2;
751 dir.d_reclen = GENERIC_DIRSIZ(&dir);
752 uiodir.dirent = &dir;
753 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
754 } else {
755 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
756 &dir.d_name[0], fid->l_fi);
757 dir.d_fileno = udf_getid(&fid->icb);
758 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
759 DT_DIR : DT_UNKNOWN;
760 dir.d_reclen = GENERIC_DIRSIZ(&dir);
761 uiodir.dirent = &dir;
762 error = udf_uiodir(&uiodir, dir.d_reclen, uio,
763 ds->this_off);
764 }
765 if (error) {
766 printf("uiomove returned %d\n", error);
767 break;
768 }
769
770 }
771
772 /* tell the calling layer whether we need to be called again */
773 *a->a_eofflag = uiodir.eofflag;
774 uio->uio_offset = ds->offset + ds->off;
775
776 if (!error)
777 error = ds->error;
778
779 udf_closedir(ds);
780
781 if (a->a_ncookies != NULL) {
782 if (error)
783 FREE(cookies, M_TEMP);
784 else {
785 *a->a_ncookies = uiodir.acookies;
786 *a->a_cookies = cookies;
787 }
788 }
789
790 return (error);
791}
792
793/* Are there any implementations out there that do soft-links? */
794static int
795udf_readlink(struct vop_readlink_args *ap)
796{
797 printf("%s called\n", __FUNCTION__);
798 return (EOPNOTSUPP);
799}
800
801static int
802udf_strategy(struct vop_strategy_args *a)
803{
804 struct buf *bp;
805 struct vnode *vp;
806 struct udf_node *node;
807 int maxsize;
808
809 bp = a->a_bp;
810 vp = bp->b_vp;
811 node = VTON(vp);
812
813 /* cd9660 has this test reversed, but it seems more logical this way */
814 if (bp->b_blkno != bp->b_lblkno) {
815 /*
816 * Files that are embedded in the fentry don't translate well
817 * to a block number. Reject.
818 */
819 if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
820 &bp->b_lblkno, &maxsize)) {
821 clrbuf(bp);
822 bp->b_blkno = -1;
823 }
824 }
825 if ((long)bp->b_blkno == -1) {
826 bufdone(bp);
827 return (0);
828 }
829 vp = node->i_devvp;
830 bp->b_dev = vp->v_rdev;
831 VOP_SPECSTRATEGY(vp, bp);
832 return (0);
833}
834
835static int
836udf_print(struct vop_print_args *a)
837{
838 printf("%s called\n", __FUNCTION__);
839 return (EOPNOTSUPP);
840}
841
842static int
843udf_bmap(struct vop_bmap_args *a)
844{
845 struct udf_node *node;
846 uint32_t max_size;
847 daddr_t lsector;
848 int error;
849
850 node = VTON(a->a_vp);
851
852 if (a->a_vpp != NULL)
853 *a->a_vpp = node->i_devvp;
854 if (a->a_bnp == NULL)
855 return (0);
856 if (a->a_runb)
857 *a->a_runb = 0;
858
859 error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector,
860 &max_size);
861 if (error)
862 return (error);
863
864 /* Translate logical to physical sector number */
865 *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
866
867 /* Punt on read-ahead for now */
868 if (a->a_runp)
869 *a->a_runp = 0;
870
871 return (0);
872}
873
874/*
875 * The all powerful VOP_LOOKUP().
876 */
877static int
878udf_lookup(struct vop_cachedlookup_args *a)
879{
880 struct vnode *dvp;
881 struct vnode *tdp = NULL;
882 struct vnode **vpp = a->a_vpp;
883 struct udf_node *node;
884 struct udf_mnt *udfmp;
885 struct fileid_desc *fid = NULL;
886 struct udf_dirstream *ds;
887 struct thread *td;
888 u_long nameiop;
889 u_long flags;
890 char *nameptr;
891 long namelen;
892 ino_t id = 0;
893 int offset, error = 0;
894 int numdirpasses, fsize;
895
896 dvp = a->a_dvp;
897 node = VTON(dvp);
898 udfmp = node->udfmp;
899 nameiop = a->a_cnp->cn_nameiop;
900 flags = a->a_cnp->cn_flags;
901 nameptr = a->a_cnp->cn_nameptr;
902 namelen = a->a_cnp->cn_namelen;
903 fsize = node->fentry->inf_len;
904 td = a->a_cnp->cn_thread;
905
906 /*
907 * If this is a LOOKUP and we've already partially searched through
908 * the directory, pick up where we left off and flag that the
909 * directory may need to be searched twice. For a full description,
910 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
911 */
912 if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
913 offset = 0;
914 numdirpasses = 1;
915 } else {
916 offset = node->diroff;
917 numdirpasses = 2;
918 nchstats.ncs_2passes++;
919 }
920
921lookloop:
922 ds = udf_opendir(node, offset, fsize, udfmp);
923
924 while ((fid = udf_getfid(ds)) != NULL) {
925
926 /* XXX Should we return an error on a bad fid? */
927 if (udf_checktag(&fid->tag, TAGID_FID)) {
928 printf("udf_lookup: Invalid tag\n");
929 error = EIO;
930 break;
931 }
932
933 /* Is this a deleted file? */
934 if (fid->file_char & UDF_FILE_CHAR_DEL)
935 continue;
936
937 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
938 if (flags & ISDOTDOT) {
939 id = udf_getid(&fid->icb);
940 break;
941 }
942 } else {
943 if (!(udf_cmpname(&fid->data[fid->l_iu],
944 nameptr, fid->l_fi, namelen))) {
945 id = udf_getid(&fid->icb);
946 break;
947 }
948 }
949 }
950
951 if (!error)
952 error = ds->error;
953
954 /* XXX Bail out here? */
955 if (error) {
956 udf_closedir(ds);
957 return (error);
958 }
959
960 /* Did we have a match? */
961 if (id) {
962 error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
963 if (!error) {
964 /*
965 * Remember where this entry was if it's the final
966 * component.
967 */
968 if ((flags & ISLASTCN) && nameiop == LOOKUP)
969 node->diroff = ds->offset + ds->off;
970 if (numdirpasses == 2)
971 nchstats.ncs_pass2++;
972 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
973 a->a_cnp->cn_flags |= PDIRUNLOCK;
974 VOP_UNLOCK(dvp, 0, td);
975 }
976
977 *vpp = tdp;
978
979 /* Put this entry in the cache */
980 if (flags & MAKEENTRY)
981 cache_enter(dvp, *vpp, a->a_cnp);
982 }
983 } else {
984 /* Name wasn't found on this pass. Do another pass? */
985 if (numdirpasses == 2) {
986 numdirpasses--;
987 offset = 0;
988 udf_closedir(ds);
989 goto lookloop;
990 }
991
992 /* Enter name into cache as non-existant */
993 if (flags & MAKEENTRY)
994 cache_enter(dvp, *vpp, a->a_cnp);
995
996 if ((flags & ISLASTCN) &&
997 (nameiop == CREATE || nameiop == RENAME)) {
998 error = EROFS;
999 } else {
1000 error = ENOENT;
1001 }
1002 }
1003
1004 udf_closedir(ds);
1005 return (error);
1006}
1007
1008static int
1009udf_reclaim(struct vop_reclaim_args *a)
1010{
1011 struct vnode *vp;
1012 struct udf_node *unode;
1013
1014 vp = a->a_vp;
1015 unode = VTON(vp);
1016
1017 cache_purge(vp);
1018 if (unode != NULL) {
1019 udf_hashrem(unode);
1020 if (unode->i_devvp) {
1021 vrele(unode->i_devvp);
1022 unode->i_devvp = 0;
1023 }
1024
1025 if (unode->fentry != NULL)
1026 FREE(unode->fentry, M_UDFFENTRY);
1027 uma_zfree(udf_zone_node, unode);
1028 vp->v_data = NULL;
1029 }
1030
1031 return (0);
1032}
1033
1034/*
1035 * Read the block and then set the data pointer to correspond with the
1036 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
1037 * to the number of bytes pointed to. If 'size' is zero, try to read in a
1038 * whole extent.
1039 * XXX 'size' is limited to the logical block size for now due to problems
1040 * with udf_read()
1041 */
1042static int
1043udf_readatoffset(struct udf_node *node, int *size, int offset, struct buf **bp, uint8_t **data)
1044{
1045 struct udf_mnt *udfmp;
1046 struct file_entry *fentry = NULL;
1047 struct buf *bp1;
1048 uint32_t max_size;
1049 daddr_t sector;
1050 int error;
1051
1052 udfmp = node->udfmp;
1053
1054 error = udf_bmap_internal(node, offset, &sector, &max_size);
1055 if (error == UDF_INVALID_BMAP) {
1056 /*
1057 * This error means that the file *data* is stored in the
1058 * allocation descriptor field of the file entry.
1059 */
1060 fentry = node->fentry;
1061 *data = &fentry->data[fentry->l_ea];
1062 *size = fentry->l_ad;
1063 *bp = NULL;
1064 return (0);
1065 } else if (error != 0) {
1066 return (error);
1067 }
1068
1069 /* Adjust the size so that it is within range */
1070 if (*size == 0 || *size > max_size)
1071 *size = max_size;
1072 *size = min(*size, MAXBSIZE);
1073
1074 if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
1075 printf("udf_readlblks returned %d\n", error);
1076 return (error);
1077 }
1078
1079 bp1 = *bp;
1080 *data = (uint8_t *)&bp1->b_data[offset % udfmp->bsize];
1081 return (0);
1082}
1083
1084/*
1085 * Translate a file offset into a logical block and then into a physical
1086 * block.
1087 */
1088static int
1089udf_bmap_internal(struct udf_node *node, uint32_t offset, daddr_t *sector, uint32_t *max_size)
1090{
1091 struct udf_mnt *udfmp;
1092 struct file_entry *fentry;
1093 void *icb;
1094 struct icb_tag *tag;
1095 uint32_t icblen = 0;
1096 daddr_t lsector;
1097 int ad_offset, ad_num = 0;
1098 int i, p_offset;
1099
1100 udfmp = node->udfmp;
1101 fentry = node->fentry;
1102 tag = &fentry->icbtag;
1103
1104 switch (tag->strat_type) {
1105 case 4:
1106 break;
1107
1108 case 4096:
1109 printf("Cannot deal with strategy4096 yet!\n");
1110 return (ENODEV);
1111
1112 default:
1113 printf("Unknown strategy type %d\n", tag->strat_type);
1114 return (ENODEV);
1115 }
1116
1117 switch (tag->flags & 0x7) {
1118 case 0:
1119 /*
1120 * The allocation descriptor field is filled with short_ad's.
1121 * If the offset is beyond the current extent, look for the
1122 * next extent.
1123 */
1124 do {
1125 offset -= icblen;
1126 ad_offset = sizeof(struct short_ad) * ad_num;
1127 if (ad_offset > fentry->l_ad) {
1128 printf("File offset out of bounds\n");
1129 return (EINVAL);
1130 }
1131 icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
1132 icblen = GETICBLEN(short_ad, icb);
1133 ad_num++;
1134 } while(offset >= icblen);
1135
1136 lsector = (offset >> udfmp->bshift) +
1137 ((struct short_ad *)(icb))->pos;
1138
1139 *max_size = GETICBLEN(short_ad, icb) - offset;
1140
1141 break;
1142 case 1:
1143 /*
1144 * The allocation descriptor field is filled with long_ad's
1145 * If the offset is beyond the current extent, look for the
1146 * next extent.
1147 */
1148 do {
1149 offset -= icblen;
1150 ad_offset = sizeof(struct long_ad) * ad_num;
1151 if (ad_offset > fentry->l_ad) {
1152 printf("File offset out of bounds\n");
1153 return (EINVAL);
1154 }
1155 icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
1156 icblen = GETICBLEN(long_ad, icb);
1157 ad_num++;
1158 } while(offset >= icblen);
1159
1160 lsector = (offset >> udfmp->bshift) +
1161 ((struct long_ad *)(icb))->loc.lb_num;
1162
1163 *max_size = GETICBLEN(long_ad, icb) - offset;
1164
1165 break;
1166 case 3:
1167 /*
1168 * This type means that the file *data* is stored in the
1169 * allocation descriptor field of the file entry.
1170 */
1171 *max_size = 0;
1172 *sector = node->hash_id + udfmp->part_start;
1173
1174 return (UDF_INVALID_BMAP);
1175 case 2:
1176 /* DirectCD does not use extended_ad's */
1177 default:
1178 printf("Unsupported allocation descriptor %d\n",
1179 tag->flags & 0x7);
1180 return (ENODEV);
1181 }
1182
1183 *sector = lsector + udfmp->part_start;
1184
1185 /*
1186 * Check the sparing table. Each entry represents the beginning of
1187 * a packet.
1188 */
1189 if (udfmp->s_table != NULL) {
1190 for (i = 0; i< udfmp->s_table_entries; i++) {
1191 p_offset = lsector - udfmp->s_table->entries[i].org;
1192 if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1193 *sector = udfmp->s_table->entries[i].map +
1194 p_offset;
1195 break;
1196 }
1197 }
1198 }
1199
1200 return (0);
1201}
528}
529
530static struct udf_dirstream *
531udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
532{
533 struct udf_dirstream *ds;
534
535 ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
536
537 ds->node = node;
538 ds->offset = offset;
539 ds->udfmp = udfmp;
540 ds->fsize = fsize;
541
542 return (ds);
543}
544
545static struct fileid_desc *
546udf_getfid(struct udf_dirstream *ds)
547{
548 struct fileid_desc *fid;
549 int error, frag_size = 0, total_fid_size;
550
551 /* End of directory? */
552 if (ds->offset + ds->off >= ds->fsize) {
553 ds->error = 0;
554 return (NULL);
555 }
556
557 /* Grab the first extent of the directory */
558 if (ds->off == 0) {
559 ds->size = 0;
560 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
561 &ds->bp, &ds->data);
562 if (error) {
563 ds->error = error;
564 return (NULL);
565 }
566 }
567
568 /*
569 * Clean up from a previous fragmented FID.
570 * XXX Is this the right place for this?
571 */
572 if (ds->fid_fragment && ds->buf != NULL) {
573 ds->fid_fragment = 0;
574 FREE(ds->buf, M_UDFFID);
575 }
576
577 fid = (struct fileid_desc*)&ds->data[ds->off];
578
579 /*
580 * Check to see if the fid is fragmented. The first test
581 * ensures that we don't wander off the end of the buffer
582 * looking for the l_iu and l_fi fields.
583 */
584 if (ds->off + UDF_FID_SIZE > ds->size ||
585 ds->off + fid->l_iu + fid->l_fi + UDF_FID_SIZE > ds->size) {
586
587 /* Copy what we have of the fid into a buffer */
588 frag_size = ds->size - ds->off;
589 if (frag_size >= ds->udfmp->bsize) {
590 printf("udf: invalid FID fragment\n");
591 ds->error = EINVAL;
592 return (NULL);
593 }
594
595 /*
596 * File ID descriptors can only be at most one
597 * logical sector in size.
598 */
599 MALLOC(ds->buf, uint8_t*, ds->udfmp->bsize, M_UDFFID,
600 M_WAITOK | M_ZERO);
601 bcopy(fid, ds->buf, frag_size);
602
603 /* Reduce all of the casting magic */
604 fid = (struct fileid_desc*)ds->buf;
605
606 if (ds->bp != NULL)
607 brelse(ds->bp);
608
609 /* Fetch the next allocation */
610 ds->offset += ds->size;
611 ds->size = 0;
612 error = udf_readatoffset(ds->node, &ds->size, ds->offset,
613 &ds->bp, &ds->data);
614 if (error) {
615 ds->error = error;
616 return (NULL);
617 }
618
619 /*
620 * If the fragment was so small that we didn't get
621 * the l_iu and l_fi fields, copy those in.
622 */
623 if (frag_size < UDF_FID_SIZE)
624 bcopy(ds->data, &ds->buf[frag_size],
625 UDF_FID_SIZE - frag_size);
626
627 /*
628 * Now that we have enough of the fid to work with,
629 * copy in the rest of the fid from the new
630 * allocation.
631 */
632 total_fid_size = UDF_FID_SIZE + fid->l_iu + fid->l_fi;
633 if (total_fid_size > ds->udfmp->bsize) {
634 printf("udf: invalid FID\n");
635 ds->error = EIO;
636 return (NULL);
637 }
638 bcopy(ds->data, &ds->buf[frag_size],
639 total_fid_size - frag_size);
640
641 ds->fid_fragment = 1;
642 } else {
643 total_fid_size = fid->l_iu + fid->l_fi + UDF_FID_SIZE;
644 }
645
646 /*
647 * Update the offset. Align on a 4 byte boundary because the
648 * UDF spec says so.
649 */
650 ds->this_off = ds->off;
651 if (!ds->fid_fragment) {
652 ds->off += (total_fid_size + 3) & ~0x03;
653 } else {
654 ds->off = (total_fid_size - frag_size + 3) & ~0x03;
655 }
656
657 return (fid);
658}
659
660static void
661udf_closedir(struct udf_dirstream *ds)
662{
663
664 if (ds->bp != NULL)
665 brelse(ds->bp);
666
667 if (ds->fid_fragment && ds->buf != NULL)
668 FREE(ds->buf, M_UDFFID);
669
670 uma_zfree(udf_zone_ds, ds);
671}
672
673static int
674udf_readdir(struct vop_readdir_args *a)
675{
676 struct vnode *vp;
677 struct uio *uio;
678 struct dirent dir;
679 struct udf_node *node;
680 struct fileid_desc *fid;
681 struct udf_uiodir uiodir;
682 struct udf_dirstream *ds;
683 u_long *cookies = NULL;
684 int ncookies;
685 int error = 0;
686
687 vp = a->a_vp;
688 uio = a->a_uio;
689 node = VTON(vp);
690 uiodir.eofflag = 1;
691
692 if (a->a_ncookies != NULL) {
693 /*
694 * Guess how many entries are needed. If we run out, this
695 * function will be called again and thing will pick up were
696 * it left off.
697 */
698 ncookies = uio->uio_resid / 8;
699 MALLOC(cookies, u_long *, sizeof(u_long) * ncookies,
700 M_TEMP, M_WAITOK);
701 if (cookies == NULL)
702 return (ENOMEM);
703 uiodir.ncookies = ncookies;
704 uiodir.cookies = cookies;
705 uiodir.acookies = 0;
706 } else {
707 uiodir.cookies = NULL;
708 }
709
710 /*
711 * Iterate through the file id descriptors. Give the parent dir
712 * entry special attention.
713 */
714 ds = udf_opendir(node, uio->uio_offset, node->fentry->inf_len,
715 node->udfmp);
716
717 while ((fid = udf_getfid(ds)) != NULL) {
718
719 /* XXX Should we return an error on a bad fid? */
720 if (udf_checktag(&fid->tag, TAGID_FID)) {
721 printf("Invalid FID tag\n");
722 udf_dumpblock(fid, UDF_FID_SIZE);
723 error = EIO;
724 break;
725 }
726
727 /* Is this a deleted file? */
728 if (fid->file_char & UDF_FILE_CHAR_DEL)
729 continue;
730
731 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
732 /* Do up the '.' and '..' entries. Dummy values are
733 * used for the cookies since the offset here is
734 * usually zero, and NFS doesn't like that value
735 */
736 dir.d_fileno = node->hash_id;
737 dir.d_type = DT_DIR;
738 dir.d_name[0] = '.';
739 dir.d_namlen = 1;
740 dir.d_reclen = GENERIC_DIRSIZ(&dir);
741 uiodir.dirent = &dir;
742 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
743 if (error)
744 break;
745
746 dir.d_fileno = udf_getid(&fid->icb);
747 dir.d_type = DT_DIR;
748 dir.d_name[0] = '.';
749 dir.d_name[1] = '.';
750 dir.d_namlen = 2;
751 dir.d_reclen = GENERIC_DIRSIZ(&dir);
752 uiodir.dirent = &dir;
753 error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
754 } else {
755 dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
756 &dir.d_name[0], fid->l_fi);
757 dir.d_fileno = udf_getid(&fid->icb);
758 dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
759 DT_DIR : DT_UNKNOWN;
760 dir.d_reclen = GENERIC_DIRSIZ(&dir);
761 uiodir.dirent = &dir;
762 error = udf_uiodir(&uiodir, dir.d_reclen, uio,
763 ds->this_off);
764 }
765 if (error) {
766 printf("uiomove returned %d\n", error);
767 break;
768 }
769
770 }
771
772 /* tell the calling layer whether we need to be called again */
773 *a->a_eofflag = uiodir.eofflag;
774 uio->uio_offset = ds->offset + ds->off;
775
776 if (!error)
777 error = ds->error;
778
779 udf_closedir(ds);
780
781 if (a->a_ncookies != NULL) {
782 if (error)
783 FREE(cookies, M_TEMP);
784 else {
785 *a->a_ncookies = uiodir.acookies;
786 *a->a_cookies = cookies;
787 }
788 }
789
790 return (error);
791}
792
793/* Are there any implementations out there that do soft-links? */
794static int
795udf_readlink(struct vop_readlink_args *ap)
796{
797 printf("%s called\n", __FUNCTION__);
798 return (EOPNOTSUPP);
799}
800
801static int
802udf_strategy(struct vop_strategy_args *a)
803{
804 struct buf *bp;
805 struct vnode *vp;
806 struct udf_node *node;
807 int maxsize;
808
809 bp = a->a_bp;
810 vp = bp->b_vp;
811 node = VTON(vp);
812
813 /* cd9660 has this test reversed, but it seems more logical this way */
814 if (bp->b_blkno != bp->b_lblkno) {
815 /*
816 * Files that are embedded in the fentry don't translate well
817 * to a block number. Reject.
818 */
819 if (udf_bmap_internal(node, bp->b_lblkno * node->udfmp->bsize,
820 &bp->b_lblkno, &maxsize)) {
821 clrbuf(bp);
822 bp->b_blkno = -1;
823 }
824 }
825 if ((long)bp->b_blkno == -1) {
826 bufdone(bp);
827 return (0);
828 }
829 vp = node->i_devvp;
830 bp->b_dev = vp->v_rdev;
831 VOP_SPECSTRATEGY(vp, bp);
832 return (0);
833}
834
835static int
836udf_print(struct vop_print_args *a)
837{
838 printf("%s called\n", __FUNCTION__);
839 return (EOPNOTSUPP);
840}
841
842static int
843udf_bmap(struct vop_bmap_args *a)
844{
845 struct udf_node *node;
846 uint32_t max_size;
847 daddr_t lsector;
848 int error;
849
850 node = VTON(a->a_vp);
851
852 if (a->a_vpp != NULL)
853 *a->a_vpp = node->i_devvp;
854 if (a->a_bnp == NULL)
855 return (0);
856 if (a->a_runb)
857 *a->a_runb = 0;
858
859 error = udf_bmap_internal(node, a->a_bn * node->udfmp->bsize, &lsector,
860 &max_size);
861 if (error)
862 return (error);
863
864 /* Translate logical to physical sector number */
865 *a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
866
867 /* Punt on read-ahead for now */
868 if (a->a_runp)
869 *a->a_runp = 0;
870
871 return (0);
872}
873
874/*
875 * The all powerful VOP_LOOKUP().
876 */
877static int
878udf_lookup(struct vop_cachedlookup_args *a)
879{
880 struct vnode *dvp;
881 struct vnode *tdp = NULL;
882 struct vnode **vpp = a->a_vpp;
883 struct udf_node *node;
884 struct udf_mnt *udfmp;
885 struct fileid_desc *fid = NULL;
886 struct udf_dirstream *ds;
887 struct thread *td;
888 u_long nameiop;
889 u_long flags;
890 char *nameptr;
891 long namelen;
892 ino_t id = 0;
893 int offset, error = 0;
894 int numdirpasses, fsize;
895
896 dvp = a->a_dvp;
897 node = VTON(dvp);
898 udfmp = node->udfmp;
899 nameiop = a->a_cnp->cn_nameiop;
900 flags = a->a_cnp->cn_flags;
901 nameptr = a->a_cnp->cn_nameptr;
902 namelen = a->a_cnp->cn_namelen;
903 fsize = node->fentry->inf_len;
904 td = a->a_cnp->cn_thread;
905
906 /*
907 * If this is a LOOKUP and we've already partially searched through
908 * the directory, pick up where we left off and flag that the
909 * directory may need to be searched twice. For a full description,
910 * see /sys/isofs/cd9660/cd9660_lookup.c:cd9660_lookup()
911 */
912 if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
913 offset = 0;
914 numdirpasses = 1;
915 } else {
916 offset = node->diroff;
917 numdirpasses = 2;
918 nchstats.ncs_2passes++;
919 }
920
921lookloop:
922 ds = udf_opendir(node, offset, fsize, udfmp);
923
924 while ((fid = udf_getfid(ds)) != NULL) {
925
926 /* XXX Should we return an error on a bad fid? */
927 if (udf_checktag(&fid->tag, TAGID_FID)) {
928 printf("udf_lookup: Invalid tag\n");
929 error = EIO;
930 break;
931 }
932
933 /* Is this a deleted file? */
934 if (fid->file_char & UDF_FILE_CHAR_DEL)
935 continue;
936
937 if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
938 if (flags & ISDOTDOT) {
939 id = udf_getid(&fid->icb);
940 break;
941 }
942 } else {
943 if (!(udf_cmpname(&fid->data[fid->l_iu],
944 nameptr, fid->l_fi, namelen))) {
945 id = udf_getid(&fid->icb);
946 break;
947 }
948 }
949 }
950
951 if (!error)
952 error = ds->error;
953
954 /* XXX Bail out here? */
955 if (error) {
956 udf_closedir(ds);
957 return (error);
958 }
959
960 /* Did we have a match? */
961 if (id) {
962 error = udf_vget(udfmp->im_mountp, id, LK_EXCLUSIVE, &tdp);
963 if (!error) {
964 /*
965 * Remember where this entry was if it's the final
966 * component.
967 */
968 if ((flags & ISLASTCN) && nameiop == LOOKUP)
969 node->diroff = ds->offset + ds->off;
970 if (numdirpasses == 2)
971 nchstats.ncs_pass2++;
972 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
973 a->a_cnp->cn_flags |= PDIRUNLOCK;
974 VOP_UNLOCK(dvp, 0, td);
975 }
976
977 *vpp = tdp;
978
979 /* Put this entry in the cache */
980 if (flags & MAKEENTRY)
981 cache_enter(dvp, *vpp, a->a_cnp);
982 }
983 } else {
984 /* Name wasn't found on this pass. Do another pass? */
985 if (numdirpasses == 2) {
986 numdirpasses--;
987 offset = 0;
988 udf_closedir(ds);
989 goto lookloop;
990 }
991
992 /* Enter name into cache as non-existant */
993 if (flags & MAKEENTRY)
994 cache_enter(dvp, *vpp, a->a_cnp);
995
996 if ((flags & ISLASTCN) &&
997 (nameiop == CREATE || nameiop == RENAME)) {
998 error = EROFS;
999 } else {
1000 error = ENOENT;
1001 }
1002 }
1003
1004 udf_closedir(ds);
1005 return (error);
1006}
1007
1008static int
1009udf_reclaim(struct vop_reclaim_args *a)
1010{
1011 struct vnode *vp;
1012 struct udf_node *unode;
1013
1014 vp = a->a_vp;
1015 unode = VTON(vp);
1016
1017 cache_purge(vp);
1018 if (unode != NULL) {
1019 udf_hashrem(unode);
1020 if (unode->i_devvp) {
1021 vrele(unode->i_devvp);
1022 unode->i_devvp = 0;
1023 }
1024
1025 if (unode->fentry != NULL)
1026 FREE(unode->fentry, M_UDFFENTRY);
1027 uma_zfree(udf_zone_node, unode);
1028 vp->v_data = NULL;
1029 }
1030
1031 return (0);
1032}
1033
1034/*
1035 * Read the block and then set the data pointer to correspond with the
1036 * offset passed in. Only read in at most 'size' bytes, and then set 'size'
1037 * to the number of bytes pointed to. If 'size' is zero, try to read in a
1038 * whole extent.
1039 * XXX 'size' is limited to the logical block size for now due to problems
1040 * with udf_read()
1041 */
1042static int
1043udf_readatoffset(struct udf_node *node, int *size, int offset, struct buf **bp, uint8_t **data)
1044{
1045 struct udf_mnt *udfmp;
1046 struct file_entry *fentry = NULL;
1047 struct buf *bp1;
1048 uint32_t max_size;
1049 daddr_t sector;
1050 int error;
1051
1052 udfmp = node->udfmp;
1053
1054 error = udf_bmap_internal(node, offset, &sector, &max_size);
1055 if (error == UDF_INVALID_BMAP) {
1056 /*
1057 * This error means that the file *data* is stored in the
1058 * allocation descriptor field of the file entry.
1059 */
1060 fentry = node->fentry;
1061 *data = &fentry->data[fentry->l_ea];
1062 *size = fentry->l_ad;
1063 *bp = NULL;
1064 return (0);
1065 } else if (error != 0) {
1066 return (error);
1067 }
1068
1069 /* Adjust the size so that it is within range */
1070 if (*size == 0 || *size > max_size)
1071 *size = max_size;
1072 *size = min(*size, MAXBSIZE);
1073
1074 if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
1075 printf("udf_readlblks returned %d\n", error);
1076 return (error);
1077 }
1078
1079 bp1 = *bp;
1080 *data = (uint8_t *)&bp1->b_data[offset % udfmp->bsize];
1081 return (0);
1082}
1083
1084/*
1085 * Translate a file offset into a logical block and then into a physical
1086 * block.
1087 */
1088static int
1089udf_bmap_internal(struct udf_node *node, uint32_t offset, daddr_t *sector, uint32_t *max_size)
1090{
1091 struct udf_mnt *udfmp;
1092 struct file_entry *fentry;
1093 void *icb;
1094 struct icb_tag *tag;
1095 uint32_t icblen = 0;
1096 daddr_t lsector;
1097 int ad_offset, ad_num = 0;
1098 int i, p_offset;
1099
1100 udfmp = node->udfmp;
1101 fentry = node->fentry;
1102 tag = &fentry->icbtag;
1103
1104 switch (tag->strat_type) {
1105 case 4:
1106 break;
1107
1108 case 4096:
1109 printf("Cannot deal with strategy4096 yet!\n");
1110 return (ENODEV);
1111
1112 default:
1113 printf("Unknown strategy type %d\n", tag->strat_type);
1114 return (ENODEV);
1115 }
1116
1117 switch (tag->flags & 0x7) {
1118 case 0:
1119 /*
1120 * The allocation descriptor field is filled with short_ad's.
1121 * If the offset is beyond the current extent, look for the
1122 * next extent.
1123 */
1124 do {
1125 offset -= icblen;
1126 ad_offset = sizeof(struct short_ad) * ad_num;
1127 if (ad_offset > fentry->l_ad) {
1128 printf("File offset out of bounds\n");
1129 return (EINVAL);
1130 }
1131 icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
1132 icblen = GETICBLEN(short_ad, icb);
1133 ad_num++;
1134 } while(offset >= icblen);
1135
1136 lsector = (offset >> udfmp->bshift) +
1137 ((struct short_ad *)(icb))->pos;
1138
1139 *max_size = GETICBLEN(short_ad, icb) - offset;
1140
1141 break;
1142 case 1:
1143 /*
1144 * The allocation descriptor field is filled with long_ad's
1145 * If the offset is beyond the current extent, look for the
1146 * next extent.
1147 */
1148 do {
1149 offset -= icblen;
1150 ad_offset = sizeof(struct long_ad) * ad_num;
1151 if (ad_offset > fentry->l_ad) {
1152 printf("File offset out of bounds\n");
1153 return (EINVAL);
1154 }
1155 icb = GETICB(long_ad, fentry, fentry->l_ea + ad_offset);
1156 icblen = GETICBLEN(long_ad, icb);
1157 ad_num++;
1158 } while(offset >= icblen);
1159
1160 lsector = (offset >> udfmp->bshift) +
1161 ((struct long_ad *)(icb))->loc.lb_num;
1162
1163 *max_size = GETICBLEN(long_ad, icb) - offset;
1164
1165 break;
1166 case 3:
1167 /*
1168 * This type means that the file *data* is stored in the
1169 * allocation descriptor field of the file entry.
1170 */
1171 *max_size = 0;
1172 *sector = node->hash_id + udfmp->part_start;
1173
1174 return (UDF_INVALID_BMAP);
1175 case 2:
1176 /* DirectCD does not use extended_ad's */
1177 default:
1178 printf("Unsupported allocation descriptor %d\n",
1179 tag->flags & 0x7);
1180 return (ENODEV);
1181 }
1182
1183 *sector = lsector + udfmp->part_start;
1184
1185 /*
1186 * Check the sparing table. Each entry represents the beginning of
1187 * a packet.
1188 */
1189 if (udfmp->s_table != NULL) {
1190 for (i = 0; i< udfmp->s_table_entries; i++) {
1191 p_offset = lsector - udfmp->s_table->entries[i].org;
1192 if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1193 *sector = udfmp->s_table->entries[i].map +
1194 p_offset;
1195 break;
1196 }
1197 }
1198 }
1199
1200 return (0);
1201}