Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/udf/udf_vnops.c
39586 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2001, 2002 Scott Long <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
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/conf.h>
40
#include <sys/buf.h>
41
#include <sys/iconv.h>
42
#include <sys/limits.h>
43
#include <sys/mount.h>
44
#include <sys/vnode.h>
45
#include <sys/dirent.h>
46
#include <sys/queue.h>
47
#include <sys/unistd.h>
48
#include <sys/endian.h>
49
50
#include <vm/uma.h>
51
52
#include <fs/udf/ecma167-udf.h>
53
#include <fs/udf/osta.h>
54
#include <fs/udf/udf.h>
55
#include <fs/udf/udf_mount.h>
56
57
extern struct iconv_functions *udf_iconv;
58
59
static vop_access_t udf_access;
60
static vop_getattr_t udf_getattr;
61
static vop_open_t udf_open;
62
static vop_ioctl_t udf_ioctl;
63
static vop_pathconf_t udf_pathconf;
64
static vop_print_t udf_print;
65
static vop_read_t udf_read;
66
static vop_readdir_t udf_readdir;
67
static vop_readlink_t udf_readlink;
68
static vop_setattr_t udf_setattr;
69
static vop_strategy_t udf_strategy;
70
static vop_bmap_t udf_bmap;
71
static vop_cachedlookup_t udf_lookup;
72
static vop_reclaim_t udf_reclaim;
73
static vop_vptofh_t udf_vptofh;
74
static int udf_readatoffset(struct udf_node *node, int *size, off_t offset,
75
struct buf **bp, uint8_t **data);
76
static int udf_bmap_internal(struct udf_node *node, off_t offset,
77
daddr_t *sector, uint32_t *max_size);
78
79
static struct vop_vector udf_vnodeops = {
80
.vop_default = &default_vnodeops,
81
82
.vop_access = udf_access,
83
.vop_bmap = udf_bmap,
84
.vop_cachedlookup = udf_lookup,
85
.vop_getattr = udf_getattr,
86
.vop_ioctl = udf_ioctl,
87
.vop_lookup = vfs_cache_lookup,
88
.vop_open = udf_open,
89
.vop_pathconf = udf_pathconf,
90
.vop_print = udf_print,
91
.vop_read = udf_read,
92
.vop_readdir = udf_readdir,
93
.vop_readlink = udf_readlink,
94
.vop_reclaim = udf_reclaim,
95
.vop_setattr = udf_setattr,
96
.vop_strategy = udf_strategy,
97
.vop_vptofh = udf_vptofh,
98
};
99
VFS_VOP_VECTOR_REGISTER(udf_vnodeops);
100
101
struct vop_vector udf_fifoops = {
102
.vop_default = &fifo_specops,
103
.vop_access = udf_access,
104
.vop_getattr = udf_getattr,
105
.vop_pathconf = udf_pathconf,
106
.vop_print = udf_print,
107
.vop_reclaim = udf_reclaim,
108
.vop_setattr = udf_setattr,
109
.vop_vptofh = udf_vptofh,
110
};
111
VFS_VOP_VECTOR_REGISTER(udf_fifoops);
112
113
static MALLOC_DEFINE(M_UDFFID, "udf_fid", "UDF FileId structure");
114
static MALLOC_DEFINE(M_UDFDS, "udf_ds", "UDF Dirstream structure");
115
116
#define UDF_INVALID_BMAP -1
117
118
int
119
udf_allocv(struct mount *mp, struct vnode **vpp, struct thread *td)
120
{
121
int error;
122
struct vnode *vp;
123
124
error = getnewvnode("udf", mp, &udf_vnodeops, &vp);
125
if (error) {
126
printf("udf_allocv: failed to allocate new vnode\n");
127
return (error);
128
}
129
130
*vpp = vp;
131
return (0);
132
}
133
134
/* Convert file entry permission (5 bits per owner/group/user) to a mode_t */
135
static mode_t
136
udf_permtomode(struct udf_node *node)
137
{
138
uint32_t perm;
139
uint16_t flags;
140
mode_t mode;
141
142
perm = le32toh(node->fentry->perm);
143
flags = le16toh(node->fentry->icbtag.flags);
144
145
mode = perm & UDF_FENTRY_PERM_USER_MASK;
146
mode |= ((perm & UDF_FENTRY_PERM_GRP_MASK) >> 2);
147
mode |= ((perm & UDF_FENTRY_PERM_OWNER_MASK) >> 4);
148
mode |= ((flags & UDF_ICB_TAG_FLAGS_STICKY) << 4);
149
mode |= ((flags & UDF_ICB_TAG_FLAGS_SETGID) << 6);
150
mode |= ((flags & UDF_ICB_TAG_FLAGS_SETUID) << 8);
151
152
return (mode);
153
}
154
155
static int
156
udf_access(struct vop_access_args *a)
157
{
158
struct vnode *vp;
159
struct udf_node *node;
160
accmode_t accmode;
161
mode_t mode;
162
163
vp = a->a_vp;
164
node = VTON(vp);
165
accmode = a->a_accmode;
166
167
if (accmode & VWRITE) {
168
switch (vp->v_type) {
169
case VDIR:
170
case VLNK:
171
case VREG:
172
return (EROFS);
173
/* NOT REACHED */
174
default:
175
break;
176
}
177
}
178
179
mode = udf_permtomode(node);
180
181
return (vaccess(vp->v_type, mode, node->fentry->uid, node->fentry->gid,
182
accmode, a->a_cred));
183
}
184
185
static int
186
udf_open(struct vop_open_args *ap)
187
{
188
struct udf_node *np = VTON(ap->a_vp);
189
uint64_t fsize;
190
191
fsize = le64toh(np->fentry->inf_len);
192
if (fsize > OFF_MAX)
193
return (EIO);
194
vnode_create_vobject(ap->a_vp, fsize, ap->a_td);
195
return 0;
196
}
197
198
static const int mon_lens[2][12] = {
199
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
200
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
201
};
202
203
static int
204
udf_isaleapyear(int year)
205
{
206
int i;
207
208
i = (year % 4) ? 0 : 1;
209
i &= (year % 100) ? 1 : 0;
210
i |= (year % 400) ? 0 : 1;
211
212
return i;
213
}
214
215
/*
216
* Timezone calculation compliments of Julian Elischer <[email protected]>.
217
*/
218
static void
219
udf_timetotimespec(struct timestamp *time, struct timespec *t)
220
{
221
int i, lpyear, daysinyear, year, startyear;
222
union {
223
uint16_t u_tz_offset;
224
int16_t s_tz_offset;
225
} tz;
226
227
/*
228
* DirectCD seems to like using bogus year values.
229
* Don't trust time->month as it will be used for an array index.
230
*/
231
year = le16toh(time->year);
232
if (year < 1970 || time->month < 1 || time->month > 12) {
233
t->tv_sec = 0;
234
t->tv_nsec = 0;
235
return;
236
}
237
238
/* Calculate the time and day */
239
t->tv_sec = time->second;
240
t->tv_sec += time->minute * 60;
241
t->tv_sec += time->hour * 3600;
242
t->tv_sec += (time->day - 1) * 3600 * 24;
243
244
/* Calculate the month */
245
lpyear = udf_isaleapyear(year);
246
t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24;
247
248
/* Speed up the calculation */
249
startyear = 1970;
250
if (year > 2009) {
251
t->tv_sec += 1262304000;
252
startyear += 40;
253
} else if (year > 1999) {
254
t->tv_sec += 946684800;
255
startyear += 30;
256
} else if (year > 1989) {
257
t->tv_sec += 631152000;
258
startyear += 20;
259
} else if (year > 1979) {
260
t->tv_sec += 315532800;
261
startyear += 10;
262
}
263
264
daysinyear = (year - startyear) * 365;
265
for (i = startyear; i < year; i++)
266
daysinyear += udf_isaleapyear(i);
267
t->tv_sec += daysinyear * 3600 * 24;
268
269
/* Calculate microseconds */
270
t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 +
271
time->usec;
272
273
/*
274
* Calculate the time zone. The timezone is 12 bit signed 2's
275
* complement, so we gotta do some extra magic to handle it right.
276
*/
277
tz.u_tz_offset = le16toh(time->type_tz);
278
tz.u_tz_offset &= 0x0fff;
279
if (tz.u_tz_offset & 0x0800)
280
tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
281
if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047))
282
t->tv_sec -= tz.s_tz_offset * 60;
283
284
return;
285
}
286
287
static int
288
udf_getattr(struct vop_getattr_args *a)
289
{
290
struct vnode *vp;
291
struct udf_node *node;
292
struct vattr *vap;
293
struct file_entry *fentry;
294
295
vp = a->a_vp;
296
vap = a->a_vap;
297
node = VTON(vp);
298
fentry = node->fentry;
299
300
vap->va_fsid = dev2udev(node->udfmp->im_dev);
301
vap->va_fileid = node->hash_id;
302
vap->va_mode = udf_permtomode(node);
303
vap->va_nlink = le16toh(fentry->link_cnt);
304
/*
305
* XXX The spec says that -1 is valid for uid/gid and indicates an
306
* invalid uid/gid. How should this be represented?
307
*/
308
vap->va_uid = (le32toh(fentry->uid) == -1) ? 0 : le32toh(fentry->uid);
309
vap->va_gid = (le32toh(fentry->gid) == -1) ? 0 : le32toh(fentry->gid);
310
udf_timetotimespec(&fentry->atime, &vap->va_atime);
311
udf_timetotimespec(&fentry->mtime, &vap->va_mtime);
312
vap->va_ctime = vap->va_mtime; /* XXX Stored as an Extended Attribute */
313
vap->va_rdev = NODEV;
314
if (vp->v_type & VDIR) {
315
/*
316
* Directories that are recorded within their ICB will show
317
* as having 0 blocks recorded. Since tradition dictates
318
* that directories consume at least one logical block,
319
* make it appear so.
320
*/
321
vap->va_size = le64toh(fentry->logblks_rec);
322
if (vap->va_size == 0)
323
vap->va_size = node->udfmp->bsize;
324
else if (vap->va_size > UINT64_MAX / node->udfmp->bsize)
325
vap->va_size = UINT64_MAX;
326
else
327
vap->va_size *= node->udfmp->bsize;
328
} else {
329
vap->va_size = le64toh(fentry->inf_len);
330
}
331
vap->va_flags = 0;
332
vap->va_gen = 1;
333
vap->va_blocksize = node->udfmp->bsize;
334
vap->va_bytes = le64toh(fentry->inf_len);
335
vap->va_type = vp->v_type;
336
vap->va_filerev = 0; /* XXX */
337
return (0);
338
}
339
340
static int
341
udf_setattr(struct vop_setattr_args *a)
342
{
343
struct vnode *vp;
344
struct vattr *vap;
345
346
vp = a->a_vp;
347
vap = a->a_vap;
348
if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
349
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
350
vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
351
return (EROFS);
352
if (vap->va_size != (u_quad_t)VNOVAL) {
353
switch (vp->v_type) {
354
case VDIR:
355
return (EISDIR);
356
case VLNK:
357
case VREG:
358
return (EROFS);
359
case VCHR:
360
case VBLK:
361
case VSOCK:
362
case VFIFO:
363
case VNON:
364
case VBAD:
365
case VMARKER:
366
return (0);
367
}
368
}
369
return (0);
370
}
371
372
/*
373
* File specific ioctls.
374
*/
375
static int
376
udf_ioctl(struct vop_ioctl_args *a)
377
{
378
printf("%s called\n", __func__);
379
return (ENOTTY);
380
}
381
382
/*
383
* I'm not sure that this has much value in a read-only filesystem, but
384
* cd9660 has it too.
385
*/
386
static int
387
udf_pathconf(struct vop_pathconf_args *a)
388
{
389
390
switch (a->a_name) {
391
case _PC_FILESIZEBITS:
392
*a->a_retval = 64;
393
return (0);
394
case _PC_LINK_MAX:
395
*a->a_retval = 65535;
396
return (0);
397
case _PC_NAME_MAX:
398
*a->a_retval = NAME_MAX;
399
return (0);
400
case _PC_SYMLINK_MAX:
401
*a->a_retval = MAXPATHLEN;
402
return (0);
403
case _PC_NO_TRUNC:
404
*a->a_retval = 1;
405
return (0);
406
case _PC_PIPE_BUF:
407
if (a->a_vp->v_type == VDIR || a->a_vp->v_type == VFIFO) {
408
*a->a_retval = PIPE_BUF;
409
return (0);
410
}
411
return (EINVAL);
412
default:
413
return (vop_stdpathconf(a));
414
}
415
}
416
417
static int
418
udf_print(struct vop_print_args *ap)
419
{
420
struct vnode *vp = ap->a_vp;
421
struct udf_node *node = VTON(vp);
422
423
printf(" ino %lu, on dev %s", (u_long)node->hash_id,
424
devtoname(node->udfmp->im_dev));
425
if (vp->v_type == VFIFO)
426
fifo_printinfo(vp);
427
printf("\n");
428
return (0);
429
}
430
431
#define lblkno(udfmp, loc) ((loc) >> (udfmp)->bshift)
432
#define blkoff(udfmp, loc) ((loc) & (udfmp)->bmask)
433
#define lblktosize(udfmp, blk) ((blk) << (udfmp)->bshift)
434
435
static inline int
436
is_data_in_fentry(const struct udf_node *node)
437
{
438
const struct file_entry *fentry = node->fentry;
439
440
return ((le16toh(fentry->icbtag.flags) & 0x7) == 3);
441
}
442
443
static int
444
udf_read(struct vop_read_args *ap)
445
{
446
struct vnode *vp = ap->a_vp;
447
struct uio *uio = ap->a_uio;
448
struct udf_node *node = VTON(vp);
449
struct udf_mnt *udfmp;
450
struct file_entry *fentry;
451
struct buf *bp;
452
uint8_t *data;
453
daddr_t lbn, rablock;
454
uint64_t len;
455
off_t diff, fsize;
456
ssize_t n;
457
int error = 0;
458
long size, on;
459
460
if (uio->uio_resid == 0)
461
return (0);
462
if (uio->uio_offset < 0)
463
return (EINVAL);
464
465
if (is_data_in_fentry(node)) {
466
fentry = node->fentry;
467
data = &fentry->data[le32toh(fentry->l_ea)];
468
fsize = le32toh(fentry->l_ad);
469
470
n = uio->uio_resid;
471
diff = fsize - uio->uio_offset;
472
if (diff <= 0)
473
return (0);
474
if (diff < n)
475
n = diff;
476
error = uiomove(data + uio->uio_offset, (int)n, uio);
477
return (error);
478
}
479
480
len = le64toh(node->fentry->inf_len);
481
if (len > OFF_MAX) {
482
/* too big, just cap to the requested length */
483
len = uio->uio_resid;
484
}
485
fsize = len;
486
udfmp = node->udfmp;
487
do {
488
lbn = lblkno(udfmp, uio->uio_offset);
489
on = blkoff(udfmp, uio->uio_offset);
490
n = min((u_int)(udfmp->bsize - on),
491
uio->uio_resid);
492
diff = fsize - uio->uio_offset;
493
if (diff <= 0)
494
return (0);
495
if (diff < n)
496
n = diff;
497
size = udfmp->bsize;
498
rablock = lbn + 1;
499
if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
500
if (lblktosize(udfmp, rablock) < fsize) {
501
error = cluster_read(vp, fsize, lbn, size,
502
NOCRED, uio->uio_resid,
503
(ap->a_ioflag >> 16), 0, &bp);
504
} else {
505
error = bread(vp, lbn, size, NOCRED, &bp);
506
}
507
} else {
508
error = bread(vp, lbn, size, NOCRED, &bp);
509
}
510
if (error != 0) {
511
brelse(bp);
512
return (error);
513
}
514
n = min(n, size - bp->b_resid);
515
516
error = uiomove(bp->b_data + on, (int)n, uio);
517
brelse(bp);
518
} while (error == 0 && uio->uio_resid > 0 && n != 0);
519
return (error);
520
}
521
522
/*
523
* Call the OSTA routines to translate the name from a CS0 dstring to a
524
* 16-bit Unicode String. Hooks need to be placed in here to translate from
525
* Unicode to the encoding that the kernel/user expects. Return the length
526
* of the translated string.
527
*/
528
static int
529
udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp)
530
{
531
unicode_t *transname;
532
char *unibuf, *unip;
533
int i, destlen;
534
ssize_t unilen = 0;
535
size_t destleft = MAXNAMLEN;
536
537
/* Convert 16-bit Unicode to destname */
538
if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
539
/* allocate a buffer big enough to hold an 8->16 bit expansion */
540
unibuf = uma_zalloc(udf_zone_trans, M_WAITOK);
541
unip = unibuf;
542
if ((unilen = (ssize_t)udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) {
543
printf("udf: Unicode translation failed\n");
544
uma_zfree(udf_zone_trans, unibuf);
545
return 0;
546
}
547
548
while (unilen > 0 && destleft > 0) {
549
udf_iconv->conv(udfmp->im_d2l, __DECONST(const char **,
550
&unibuf), (size_t *)&unilen, (char **)&destname,
551
&destleft);
552
/* Unconverted character found */
553
if (unilen > 0 && destleft > 0) {
554
*destname++ = '?';
555
destleft--;
556
unibuf += 2;
557
unilen -= 2;
558
}
559
}
560
uma_zfree(udf_zone_trans, unip);
561
*destname = '\0';
562
destlen = MAXNAMLEN - (int)destleft;
563
} else {
564
/* allocate a buffer big enough to hold an 8->16 bit expansion */
565
transname = uma_zalloc(udf_zone_trans, M_WAITOK);
566
567
if ((unilen = (ssize_t)udf_UncompressUnicode(len, cs0string, transname)) == -1) {
568
printf("udf: Unicode translation failed\n");
569
uma_zfree(udf_zone_trans, transname);
570
return 0;
571
}
572
573
for (i = 0; i < unilen ; i++) {
574
if (transname[i] & 0xff00) {
575
destname[i] = '.'; /* Fudge the 16bit chars */
576
} else {
577
destname[i] = transname[i] & 0xff;
578
}
579
}
580
uma_zfree(udf_zone_trans, transname);
581
destname[unilen] = 0;
582
destlen = (int)unilen;
583
}
584
585
return (destlen);
586
}
587
588
/*
589
* Compare a CS0 dstring with a name passed in from the VFS layer. Return
590
* 0 on a successful match, nonzero otherwise. Unicode work may need to be done
591
* here also.
592
*/
593
static int
594
udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp)
595
{
596
char *transname;
597
int error = 0;
598
599
/* This is overkill, but not worth creating a new zone */
600
transname = uma_zalloc(udf_zone_trans, M_WAITOK);
601
602
cs0len = udf_transname(cs0string, transname, cs0len, udfmp);
603
604
/* Easy check. If they aren't the same length, they aren't equal */
605
if ((cs0len == 0) || (cs0len != cmplen))
606
error = -1;
607
else
608
error = bcmp(transname, cmpname, cmplen);
609
610
uma_zfree(udf_zone_trans, transname);
611
return (error);
612
}
613
614
struct udf_uiodir {
615
struct dirent *dirent;
616
uint64_t *cookies;
617
int ncookies;
618
int acookies;
619
int eofflag;
620
};
621
622
static int
623
udf_uiodir(struct udf_uiodir *uiodir, int de_size, struct uio *uio, long cookie)
624
{
625
if (uiodir->cookies != NULL) {
626
if (++uiodir->acookies > uiodir->ncookies) {
627
uiodir->eofflag = 0;
628
return (-1);
629
}
630
*uiodir->cookies++ = cookie;
631
}
632
633
if (uio->uio_resid < de_size) {
634
uiodir->eofflag = 0;
635
return (-1);
636
}
637
638
return (uiomove(uiodir->dirent, de_size, uio));
639
}
640
641
static struct udf_dirstream *
642
udf_opendir(struct udf_node *node, int offset, int fsize, struct udf_mnt *udfmp)
643
{
644
struct udf_dirstream *ds;
645
646
ds = uma_zalloc(udf_zone_ds, M_WAITOK | M_ZERO);
647
648
ds->node = node;
649
ds->offset = offset;
650
ds->udfmp = udfmp;
651
ds->fsize = fsize;
652
653
return (ds);
654
}
655
656
static struct fileid_desc *
657
udf_getfid(struct udf_dirstream *ds)
658
{
659
struct fileid_desc *fid;
660
int error, frag_size = 0, total_fid_size;
661
662
/* End of directory? */
663
if (ds->offset + ds->off >= ds->fsize) {
664
ds->error = 0;
665
return (NULL);
666
}
667
668
/* Grab the first extent of the directory */
669
if (ds->off == 0) {
670
ds->size = 0;
671
error = udf_readatoffset(ds->node, &ds->size, ds->offset,
672
&ds->bp, &ds->data);
673
if (error) {
674
ds->error = error;
675
if (ds->bp != NULL)
676
brelse(ds->bp);
677
return (NULL);
678
}
679
}
680
681
/*
682
* Clean up from a previous fragmented FID.
683
* XXX Is this the right place for this?
684
*/
685
if (ds->fid_fragment && ds->buf != NULL) {
686
ds->fid_fragment = 0;
687
free(ds->buf, M_UDFFID);
688
}
689
690
fid = (struct fileid_desc*)&ds->data[ds->off];
691
692
/*
693
* Check to see if the fid is fragmented. The first test
694
* ensures that we don't wander off the end of the buffer
695
* looking for the l_iu and l_fi fields.
696
*/
697
if (ds->off + UDF_FID_SIZE > ds->size ||
698
ds->off + le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE > ds->size){
699
/* Copy what we have of the fid into a buffer */
700
frag_size = ds->size - ds->off;
701
if (frag_size >= ds->udfmp->bsize) {
702
printf("udf: invalid FID fragment\n");
703
ds->error = EINVAL;
704
return (NULL);
705
}
706
707
/*
708
* File ID descriptors can only be at most one
709
* logical sector in size.
710
*/
711
ds->buf = malloc(ds->udfmp->bsize, M_UDFFID,
712
M_WAITOK | M_ZERO);
713
bcopy(fid, ds->buf, frag_size);
714
715
/* Reduce all of the casting magic */
716
fid = (struct fileid_desc*)ds->buf;
717
718
if (ds->bp != NULL)
719
brelse(ds->bp);
720
721
/* Fetch the next allocation */
722
ds->offset += ds->size;
723
ds->size = 0;
724
error = udf_readatoffset(ds->node, &ds->size, ds->offset,
725
&ds->bp, &ds->data);
726
if (error) {
727
ds->error = error;
728
return (NULL);
729
}
730
731
/*
732
* If the fragment was so small that we didn't get
733
* the l_iu and l_fi fields, copy those in.
734
*/
735
if (frag_size < UDF_FID_SIZE)
736
bcopy(ds->data, &ds->buf[frag_size],
737
UDF_FID_SIZE - frag_size);
738
739
/*
740
* Now that we have enough of the fid to work with,
741
* copy in the rest of the fid from the new
742
* allocation.
743
*/
744
total_fid_size = UDF_FID_SIZE + le16toh(fid->l_iu) + fid->l_fi;
745
if (total_fid_size > ds->udfmp->bsize) {
746
printf("udf: invalid FID\n");
747
ds->error = EIO;
748
return (NULL);
749
}
750
bcopy(ds->data, &ds->buf[frag_size],
751
total_fid_size - frag_size);
752
753
ds->fid_fragment = 1;
754
} else {
755
total_fid_size = le16toh(fid->l_iu) + fid->l_fi + UDF_FID_SIZE;
756
}
757
758
/*
759
* Update the offset. Align on a 4 byte boundary because the
760
* UDF spec says so.
761
*/
762
ds->this_off = ds->offset + ds->off;
763
if (!ds->fid_fragment) {
764
ds->off += (total_fid_size + 3) & ~0x03;
765
} else {
766
ds->off = (total_fid_size - frag_size + 3) & ~0x03;
767
}
768
769
return (fid);
770
}
771
772
static void
773
udf_closedir(struct udf_dirstream *ds)
774
{
775
776
if (ds->bp != NULL)
777
brelse(ds->bp);
778
779
if (ds->fid_fragment && ds->buf != NULL)
780
free(ds->buf, M_UDFFID);
781
782
uma_zfree(udf_zone_ds, ds);
783
}
784
785
static int
786
udf_readdir(struct vop_readdir_args *a)
787
{
788
struct vnode *vp;
789
struct uio *uio;
790
struct dirent dir;
791
struct udf_node *node;
792
struct udf_mnt *udfmp;
793
struct fileid_desc *fid;
794
struct udf_uiodir uiodir;
795
struct udf_dirstream *ds;
796
uint64_t *cookies = NULL;
797
uint64_t len;
798
int ncookies;
799
int error = 0;
800
801
vp = a->a_vp;
802
uio = a->a_uio;
803
node = VTON(vp);
804
udfmp = node->udfmp;
805
uiodir.eofflag = 1;
806
807
if (a->a_ncookies != NULL) {
808
/*
809
* Guess how many entries are needed. If we run out, this
810
* function will be called again and thing will pick up were
811
* it left off.
812
*/
813
ncookies = uio->uio_resid / 8;
814
cookies = malloc(sizeof(*cookies) * ncookies, M_TEMP, M_WAITOK);
815
uiodir.ncookies = ncookies;
816
uiodir.cookies = cookies;
817
uiodir.acookies = 0;
818
} else {
819
uiodir.cookies = NULL;
820
}
821
822
/*
823
* Iterate through the file id descriptors. Give the parent dir
824
* entry special attention.
825
*/
826
len = le64toh(node->fentry->inf_len);
827
if (len > INT_MAX) {
828
/* too big, just cap to INT_MAX */
829
len = INT_MAX;
830
}
831
ds = udf_opendir(node, uio->uio_offset, len, node->udfmp);
832
833
while ((fid = udf_getfid(ds)) != NULL) {
834
/* XXX Should we return an error on a bad fid? */
835
if (udf_checktag(&fid->tag, TAGID_FID)) {
836
printf("Invalid FID tag\n");
837
hexdump(fid, UDF_FID_SIZE, NULL, 0);
838
error = EIO;
839
break;
840
}
841
842
/* Is this a deleted file? */
843
if (fid->file_char & UDF_FILE_CHAR_DEL)
844
continue;
845
846
if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
847
/* Do up the '.' and '..' entries. Dummy values are
848
* used for the cookies since the offset here is
849
* usually zero, and NFS doesn't like that value
850
*/
851
dir.d_fileno = node->hash_id;
852
dir.d_type = DT_DIR;
853
dir.d_name[0] = '.';
854
dir.d_namlen = 1;
855
dir.d_reclen = GENERIC_DIRSIZ(&dir);
856
dir.d_off = 1;
857
dirent_terminate(&dir);
858
uiodir.dirent = &dir;
859
error = udf_uiodir(&uiodir, dir.d_reclen, uio, 1);
860
if (error)
861
break;
862
863
dir.d_fileno = udf_getid(&fid->icb);
864
dir.d_type = DT_DIR;
865
dir.d_name[0] = '.';
866
dir.d_name[1] = '.';
867
dir.d_namlen = 2;
868
dir.d_reclen = GENERIC_DIRSIZ(&dir);
869
dir.d_off = 2;
870
dirent_terminate(&dir);
871
uiodir.dirent = &dir;
872
error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2);
873
} else {
874
dir.d_namlen = udf_transname(&fid->data[fid->l_iu],
875
&dir.d_name[0], fid->l_fi, udfmp);
876
dir.d_fileno = udf_getid(&fid->icb);
877
dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ?
878
DT_DIR : DT_UNKNOWN;
879
dir.d_reclen = GENERIC_DIRSIZ(&dir);
880
dir.d_off = ds->this_off;
881
dirent_terminate(&dir);
882
uiodir.dirent = &dir;
883
error = udf_uiodir(&uiodir, dir.d_reclen, uio,
884
ds->this_off);
885
}
886
if (error)
887
break;
888
uio->uio_offset = ds->offset + ds->off;
889
}
890
891
/* tell the calling layer whether we need to be called again */
892
*a->a_eofflag = uiodir.eofflag;
893
894
if (error < 0)
895
error = 0;
896
if (!error)
897
error = ds->error;
898
899
udf_closedir(ds);
900
901
if (a->a_ncookies != NULL) {
902
if (error)
903
free(cookies, M_TEMP);
904
else {
905
*a->a_ncookies = uiodir.acookies;
906
*a->a_cookies = cookies;
907
}
908
}
909
910
return (error);
911
}
912
913
static int
914
udf_readlink(struct vop_readlink_args *ap)
915
{
916
struct path_component *pc, *end;
917
struct vnode *vp;
918
struct uio uio;
919
struct iovec iov[1];
920
struct udf_node *node;
921
void *buf;
922
char *cp;
923
uint64_t len;
924
int error, root;
925
926
/*
927
* A symbolic link in UDF is a list of variable-length path
928
* component structures. We build a pathname in the caller's
929
* uio by traversing this list.
930
*/
931
vp = ap->a_vp;
932
node = VTON(vp);
933
len = le64toh(node->fentry->inf_len);
934
if (len > MAXPATHLEN)
935
return (EIO);
936
buf = malloc(len, M_DEVBUF, M_WAITOK);
937
iov[0].iov_len = len;
938
iov[0].iov_base = buf;
939
uio.uio_iov = iov;
940
uio.uio_iovcnt = 1;
941
uio.uio_offset = 0;
942
uio.uio_resid = iov[0].iov_len;
943
uio.uio_segflg = UIO_SYSSPACE;
944
uio.uio_rw = UIO_READ;
945
uio.uio_td = curthread;
946
error = VOP_READ(vp, &uio, 0, ap->a_cred);
947
if (error)
948
goto error;
949
950
pc = buf;
951
end = (void *)((char *)buf + len);
952
root = 0;
953
while (pc < end) {
954
switch (pc->type) {
955
case UDF_PATH_ROOT:
956
/* Only allow this at the beginning of a path. */
957
if ((void *)pc != buf) {
958
error = EINVAL;
959
goto error;
960
}
961
cp = "/";
962
len = 1;
963
root = 1;
964
break;
965
case UDF_PATH_DOT:
966
cp = ".";
967
len = 1;
968
break;
969
case UDF_PATH_DOTDOT:
970
cp = "..";
971
len = 2;
972
break;
973
case UDF_PATH_PATH:
974
if (pc->length == 0) {
975
error = EINVAL;
976
goto error;
977
}
978
/*
979
* XXX: We only support CS8 which appears to map
980
* to ASCII directly.
981
*/
982
switch (pc->identifier[0]) {
983
case 8:
984
cp = pc->identifier + 1;
985
len = pc->length - 1;
986
break;
987
default:
988
error = EOPNOTSUPP;
989
goto error;
990
}
991
break;
992
default:
993
error = EINVAL;
994
goto error;
995
}
996
997
/*
998
* If this is not the first component, insert a path
999
* separator.
1000
*/
1001
if (pc != buf) {
1002
/* If we started with root we already have a "/". */
1003
if (root)
1004
goto skipslash;
1005
root = 0;
1006
if (ap->a_uio->uio_resid < 1) {
1007
error = ENAMETOOLONG;
1008
goto error;
1009
}
1010
error = uiomove("/", 1, ap->a_uio);
1011
if (error)
1012
break;
1013
}
1014
skipslash:
1015
1016
/* Append string at 'cp' of length 'len' to our path. */
1017
if (len > ap->a_uio->uio_resid) {
1018
error = ENAMETOOLONG;
1019
goto error;
1020
}
1021
error = uiomove(cp, len, ap->a_uio);
1022
if (error)
1023
break;
1024
1025
/* Advance to next component. */
1026
pc = (void *)((char *)pc + 4 + pc->length);
1027
}
1028
error:
1029
free(buf, M_DEVBUF);
1030
return (error);
1031
}
1032
1033
static int
1034
udf_strategy(struct vop_strategy_args *a)
1035
{
1036
struct buf *bp;
1037
struct vnode *vp;
1038
struct udf_node *node;
1039
struct bufobj *bo;
1040
off_t offset;
1041
uint32_t maxsize;
1042
daddr_t sector;
1043
int error;
1044
1045
bp = a->a_bp;
1046
vp = a->a_vp;
1047
node = VTON(vp);
1048
1049
if (bp->b_blkno == bp->b_lblkno) {
1050
offset = lblktosize(node->udfmp, bp->b_lblkno);
1051
error = udf_bmap_internal(node, offset, &sector, &maxsize);
1052
if (error) {
1053
clrbuf(bp);
1054
bp->b_blkno = -1;
1055
bufdone(bp);
1056
return (0);
1057
}
1058
/* bmap gives sector numbers, bio works with device blocks */
1059
bp->b_blkno = sector << (node->udfmp->bshift - DEV_BSHIFT);
1060
}
1061
bo = node->udfmp->im_bo;
1062
bp->b_iooffset = dbtob(bp->b_blkno);
1063
BO_STRATEGY(bo, bp);
1064
return (0);
1065
}
1066
1067
static int
1068
udf_bmap(struct vop_bmap_args *a)
1069
{
1070
struct udf_node *node;
1071
uint32_t max_size;
1072
daddr_t lsector;
1073
int nblk;
1074
int error;
1075
1076
node = VTON(a->a_vp);
1077
1078
if (a->a_bop != NULL)
1079
*a->a_bop = &node->udfmp->im_devvp->v_bufobj;
1080
if (a->a_bnp == NULL)
1081
return (0);
1082
if (a->a_runb)
1083
*a->a_runb = 0;
1084
1085
/*
1086
* UDF_INVALID_BMAP means data embedded into fentry, this is an internal
1087
* error that should not be propagated to calling code.
1088
* Most obvious mapping for this error is EOPNOTSUPP as we can not truly
1089
* translate block numbers in this case.
1090
* Incidentally, this return code will make vnode pager to use VOP_READ
1091
* to get data for mmap-ed pages and udf_read knows how to do the right
1092
* thing for this kind of files.
1093
*/
1094
error = udf_bmap_internal(node, a->a_bn << node->udfmp->bshift,
1095
&lsector, &max_size);
1096
if (error == UDF_INVALID_BMAP)
1097
return (EOPNOTSUPP);
1098
if (error)
1099
return (error);
1100
1101
/* Translate logical to physical sector number */
1102
*a->a_bnp = lsector << (node->udfmp->bshift - DEV_BSHIFT);
1103
1104
/*
1105
* Determine maximum number of readahead blocks following the
1106
* requested block.
1107
*/
1108
if (a->a_runp) {
1109
nblk = (max_size >> node->udfmp->bshift) - 1;
1110
if (nblk <= 0)
1111
*a->a_runp = 0;
1112
else if (nblk >= (MAXBSIZE >> node->udfmp->bshift))
1113
*a->a_runp = (MAXBSIZE >> node->udfmp->bshift) - 1;
1114
else
1115
*a->a_runp = nblk;
1116
}
1117
1118
if (a->a_runb) {
1119
*a->a_runb = 0;
1120
}
1121
1122
return (0);
1123
}
1124
1125
/*
1126
* The all powerful VOP_LOOKUP().
1127
*/
1128
static int
1129
udf_lookup(struct vop_cachedlookup_args *a)
1130
{
1131
struct vnode *dvp;
1132
struct vnode *tdp = NULL;
1133
struct vnode **vpp = a->a_vpp;
1134
struct udf_node *node;
1135
struct udf_mnt *udfmp;
1136
struct fileid_desc *fid = NULL;
1137
struct udf_dirstream *ds;
1138
uint64_t fsize;
1139
u_long nameiop;
1140
u_long flags;
1141
char *nameptr;
1142
long namelen;
1143
ino_t id = 0;
1144
int offset, error = 0;
1145
int lkflags, ltype, numdirpasses;
1146
1147
dvp = a->a_dvp;
1148
node = VTON(dvp);
1149
udfmp = node->udfmp;
1150
nameiop = a->a_cnp->cn_nameiop;
1151
flags = a->a_cnp->cn_flags;
1152
lkflags = a->a_cnp->cn_lkflags;
1153
nameptr = a->a_cnp->cn_nameptr;
1154
namelen = a->a_cnp->cn_namelen;
1155
fsize = le64toh(node->fentry->inf_len);
1156
if (fsize > INT_MAX) {
1157
/* too big, just cap to INT_MAX */
1158
fsize = INT_MAX;
1159
}
1160
1161
/*
1162
* If this is a LOOKUP and we've already partially searched through
1163
* the directory, pick up where we left off and flag that the
1164
* directory may need to be searched twice. For a full description,
1165
* see /sys/fs/cd9660/cd9660_lookup.c:cd9660_lookup()
1166
*/
1167
if (nameiop != LOOKUP || node->diroff == 0 || node->diroff > fsize) {
1168
offset = 0;
1169
numdirpasses = 1;
1170
} else {
1171
offset = node->diroff;
1172
numdirpasses = 2;
1173
nchstats.ncs_2passes++;
1174
}
1175
1176
lookloop:
1177
ds = udf_opendir(node, offset, fsize, udfmp);
1178
1179
while ((fid = udf_getfid(ds)) != NULL) {
1180
/* XXX Should we return an error on a bad fid? */
1181
if (udf_checktag(&fid->tag, TAGID_FID)) {
1182
printf("udf_lookup: Invalid tag\n");
1183
error = EIO;
1184
break;
1185
}
1186
1187
/* Is this a deleted file? */
1188
if (fid->file_char & UDF_FILE_CHAR_DEL)
1189
continue;
1190
1191
if ((fid->l_fi == 0) && (fid->file_char & UDF_FILE_CHAR_PAR)) {
1192
if (flags & ISDOTDOT) {
1193
id = udf_getid(&fid->icb);
1194
break;
1195
}
1196
} else {
1197
if (!(udf_cmpname(&fid->data[fid->l_iu],
1198
nameptr, fid->l_fi, namelen, udfmp))) {
1199
id = udf_getid(&fid->icb);
1200
break;
1201
}
1202
}
1203
}
1204
1205
if (!error)
1206
error = ds->error;
1207
1208
/* XXX Bail out here? */
1209
if (error) {
1210
udf_closedir(ds);
1211
return (error);
1212
}
1213
1214
/* Did we have a match? */
1215
if (id) {
1216
/*
1217
* Remember where this entry was if it's the final
1218
* component.
1219
*/
1220
if ((flags & ISLASTCN) && nameiop == LOOKUP)
1221
node->diroff = ds->offset + ds->off;
1222
if (numdirpasses == 2)
1223
nchstats.ncs_pass2++;
1224
udf_closedir(ds);
1225
1226
if (flags & ISDOTDOT) {
1227
error = vn_vget_ino(dvp, id, lkflags, &tdp);
1228
} else if (node->hash_id == id) {
1229
vref(dvp); /* we want ourself, ie "." */
1230
/*
1231
* When we lookup "." we still can be asked to lock it
1232
* differently.
1233
*/
1234
ltype = lkflags & LK_TYPE_MASK;
1235
if (ltype != VOP_ISLOCKED(dvp)) {
1236
if (ltype == LK_EXCLUSIVE)
1237
vn_lock(dvp, LK_UPGRADE | LK_RETRY);
1238
else /* if (ltype == LK_SHARED) */
1239
vn_lock(dvp, LK_DOWNGRADE | LK_RETRY);
1240
}
1241
tdp = dvp;
1242
} else
1243
error = udf_vget(udfmp->im_mountp, id, lkflags, &tdp);
1244
if (!error) {
1245
*vpp = tdp;
1246
/* Put this entry in the cache */
1247
if (flags & MAKEENTRY)
1248
cache_enter(dvp, *vpp, a->a_cnp);
1249
}
1250
} else {
1251
/* Name wasn't found on this pass. Do another pass? */
1252
if (numdirpasses == 2) {
1253
numdirpasses--;
1254
offset = 0;
1255
udf_closedir(ds);
1256
goto lookloop;
1257
}
1258
udf_closedir(ds);
1259
1260
/* Enter name into cache as non-existant */
1261
if (flags & MAKEENTRY)
1262
cache_enter(dvp, *vpp, a->a_cnp);
1263
1264
if ((flags & ISLASTCN) &&
1265
(nameiop == CREATE || nameiop == RENAME)) {
1266
error = EROFS;
1267
} else {
1268
error = ENOENT;
1269
}
1270
}
1271
1272
return (error);
1273
}
1274
1275
static int
1276
udf_reclaim(struct vop_reclaim_args *a)
1277
{
1278
struct vnode *vp;
1279
struct udf_node *unode;
1280
1281
vp = a->a_vp;
1282
unode = VTON(vp);
1283
1284
if (unode != NULL) {
1285
vfs_hash_remove(vp);
1286
1287
if (unode->fentry != NULL)
1288
free(unode->fentry, M_UDFFENTRY);
1289
uma_zfree(udf_zone_node, unode);
1290
vp->v_data = NULL;
1291
}
1292
1293
return (0);
1294
}
1295
1296
static int
1297
udf_vptofh(struct vop_vptofh_args *a)
1298
{
1299
struct udf_node *node;
1300
struct ifid *ifhp;
1301
_Static_assert(sizeof(struct ifid) <= sizeof(struct fid),
1302
"struct ifid cannot be larger than struct fid");
1303
1304
node = VTON(a->a_vp);
1305
ifhp = (struct ifid *)a->a_fhp;
1306
ifhp->ifid_len = sizeof(struct ifid);
1307
ifhp->ifid_ino = node->hash_id;
1308
1309
return (0);
1310
}
1311
1312
/*
1313
* Read the block and then set the data pointer to correspond with the
1314
* offset passed in. Only read in at most 'size' bytes, and then set 'size'
1315
* to the number of bytes pointed to. If 'size' is zero, try to read in a
1316
* whole extent.
1317
*
1318
* Note that *bp may be assigned error or not.
1319
*
1320
*/
1321
static int
1322
udf_readatoffset(struct udf_node *node, int *size, off_t offset,
1323
struct buf **bp, uint8_t **data)
1324
{
1325
struct udf_mnt *udfmp = node->udfmp;
1326
struct vnode *vp = node->i_vnode;
1327
struct file_entry *fentry;
1328
struct buf *bp1;
1329
uint32_t max_size;
1330
daddr_t sector;
1331
off_t off;
1332
int adj_size;
1333
int error;
1334
1335
/*
1336
* This call is made *not* only to detect UDF_INVALID_BMAP case,
1337
* max_size is used as an ad-hoc read-ahead hint for "normal" case.
1338
*/
1339
error = udf_bmap_internal(node, offset, &sector, &max_size);
1340
if (error == UDF_INVALID_BMAP) {
1341
/*
1342
* This error means that the file *data* is stored in the
1343
* allocation descriptor field of the file entry.
1344
*/
1345
fentry = node->fentry;
1346
*data = &fentry->data[le32toh(fentry->l_ea)];
1347
*size = le32toh(fentry->l_ad);
1348
if (offset >= *size)
1349
*size = 0;
1350
else {
1351
*data += offset;
1352
*size -= offset;
1353
}
1354
return (0);
1355
} else if (error != 0) {
1356
return (error);
1357
}
1358
1359
/* Adjust the size so that it is within range */
1360
if (*size == 0 || *size > max_size)
1361
*size = max_size;
1362
1363
/*
1364
* Because we will read starting at block boundary, we need to adjust
1365
* how much we need to read so that all promised data is in.
1366
* Also, we can't promise to read more than MAXBSIZE bytes starting
1367
* from block boundary, so adjust what we promise too.
1368
*/
1369
off = blkoff(udfmp, offset);
1370
*size = min(*size, MAXBSIZE - off);
1371
adj_size = (*size + off + udfmp->bmask) & ~udfmp->bmask;
1372
*bp = NULL;
1373
if ((error = bread(vp, lblkno(udfmp, offset), adj_size, NOCRED, bp))) {
1374
printf("warning: udf_readlblks returned error %d\n", error);
1375
/* note: *bp may be non-NULL */
1376
return (error);
1377
}
1378
1379
bp1 = *bp;
1380
*data = (uint8_t *)&bp1->b_data[offset & udfmp->bmask];
1381
return (0);
1382
}
1383
1384
/*
1385
* Translate a file offset into a logical block and then into a physical
1386
* block.
1387
* max_size - maximum number of bytes that can be read starting from given
1388
* offset, rather than beginning of calculated sector number
1389
*/
1390
static int
1391
udf_bmap_internal(struct udf_node *node, off_t offset, daddr_t *sector,
1392
uint32_t *max_size)
1393
{
1394
struct udf_mnt *udfmp;
1395
struct file_entry *fentry;
1396
void *icb;
1397
struct icb_tag *tag;
1398
uint32_t icblen = 0;
1399
daddr_t lsector;
1400
int ad_offset, ad_num = 0;
1401
int i, p_offset;
1402
1403
udfmp = node->udfmp;
1404
fentry = node->fentry;
1405
tag = &fentry->icbtag;
1406
1407
switch (le16toh(tag->strat_type)) {
1408
case 4:
1409
break;
1410
1411
case 4096:
1412
printf("Cannot deal with strategy4096 yet!\n");
1413
return (ENODEV);
1414
1415
default:
1416
printf("Unknown strategy type %d\n", tag->strat_type);
1417
return (ENODEV);
1418
}
1419
1420
switch (le16toh(tag->flags) & 0x7) {
1421
case 0:
1422
/*
1423
* The allocation descriptor field is filled with short_ad's.
1424
* If the offset is beyond the current extent, look for the
1425
* next extent.
1426
*/
1427
do {
1428
offset -= icblen;
1429
ad_offset = sizeof(struct short_ad) * ad_num;
1430
if (ad_offset > le32toh(fentry->l_ad)) {
1431
printf("File offset out of bounds\n");
1432
return (EINVAL);
1433
}
1434
icb = GETICB(short_ad, fentry,
1435
le32toh(fentry->l_ea) + ad_offset);
1436
icblen = GETICBLEN(short_ad, icb);
1437
ad_num++;
1438
} while(offset >= icblen);
1439
1440
lsector = (offset >> udfmp->bshift) +
1441
le32toh(((struct short_ad *)(icb))->pos);
1442
1443
*max_size = icblen - offset;
1444
1445
break;
1446
case 1:
1447
/*
1448
* The allocation descriptor field is filled with long_ad's
1449
* If the offset is beyond the current extent, look for the
1450
* next extent.
1451
*/
1452
do {
1453
offset -= icblen;
1454
ad_offset = sizeof(struct long_ad) * ad_num;
1455
if (ad_offset > le32toh(fentry->l_ad)) {
1456
printf("File offset out of bounds\n");
1457
return (EINVAL);
1458
}
1459
icb = GETICB(long_ad, fentry,
1460
le32toh(fentry->l_ea) + ad_offset);
1461
icblen = GETICBLEN(long_ad, icb);
1462
ad_num++;
1463
} while(offset >= icblen);
1464
1465
lsector = (offset >> udfmp->bshift) +
1466
le32toh(((struct long_ad *)(icb))->loc.lb_num);
1467
1468
*max_size = icblen - offset;
1469
1470
break;
1471
case 3:
1472
/*
1473
* This type means that the file *data* is stored in the
1474
* allocation descriptor field of the file entry.
1475
*/
1476
*max_size = 0;
1477
*sector = node->hash_id + udfmp->part_start;
1478
1479
return (UDF_INVALID_BMAP);
1480
case 2:
1481
/* DirectCD does not use extended_ad's */
1482
default:
1483
printf("Unsupported allocation descriptor %d\n",
1484
tag->flags & 0x7);
1485
return (ENODEV);
1486
}
1487
1488
*sector = lsector + udfmp->part_start;
1489
1490
/*
1491
* Check the sparing table. Each entry represents the beginning of
1492
* a packet.
1493
*/
1494
if (udfmp->s_table != NULL) {
1495
for (i = 0; i< udfmp->s_table_entries; i++) {
1496
p_offset =
1497
lsector - le32toh(udfmp->s_table->entries[i].org);
1498
if ((p_offset < udfmp->p_sectors) && (p_offset >= 0)) {
1499
*sector =
1500
le32toh(udfmp->s_table->entries[i].map) +
1501
p_offset;
1502
break;
1503
}
1504
}
1505
}
1506
1507
return (0);
1508
}
1509
1510