1 /* $NetBSD: cd9660.c,v 1.23 2007/11/24 13:20:54 isaki Exp $ */
4 * Copyright (C) 1996 Wolfgang Solfrank.
5 * Copyright (C) 1996 TooLs GmbH.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Stand-alone ISO9660 file reading package.
37 * Note: This doesn't support Rock Ridge extensions, extended attributes,
38 * blocksizes other than 2048 bytes, multi-extent files, etc.
40 #include <sys/param.h>
42 #include <lib/libkern/libkern.h>
46 #include <fs/cd9660/iso.h>
52 * XXX Does not currently implement:
54 * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
55 * XXX LIBSA_FS_SINGLECOMPONENT
59 off_t off
; /* Current offset within file */
60 daddr_t bno
; /* Starting block number */
61 off_t size
; /* Size of file */
65 char namlen
[ISODCL( 1, 1)]; /* 711 */
66 char extlen
[ISODCL( 2, 2)]; /* 711 */
67 char block
[ISODCL( 3, 6)]; /* 732 */
68 char parent
[ISODCL( 7, 8)]; /* 722 */
72 #define PTSIZE(pp) roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
74 #define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
76 static int pnmatch(const char *, struct ptable_ent
*);
77 static int dirmatch(const char *, struct iso_directory_record
*);
80 pnmatch(const char *path
, struct ptable_ent
*pp
)
86 for (i
= isonum_711(pp
->namlen
); --i
>= 0; path
++, cp
++) {
87 if (toupper(*path
) == *cp
)
97 dirmatch(const char *path
, struct iso_directory_record
*dp
)
102 /* This needs to be a regular file */
103 if (dp
->flags
[0] & 6)
107 for (i
= isonum_711(dp
->name_len
); --i
>= 0; path
++, cp
++) {
110 if (toupper(*path
) == *cp
)
117 * Allow stripping of trailing dots and the version number.
118 * Note that this will find the first instead of the last version
121 if (i
>= 0 && (*cp
== ';' || *cp
== '.')) {
122 /* This is to prevent matching of numeric extensions */
123 if (*cp
== '.' && cp
[1] != ';')
126 if (*++cp
!= ';' && (*cp
< '0' || *cp
> '9'))
133 cd9660_open(const char *path
, struct open_file
*f
)
137 struct iso_primary_descriptor
*vd
;
138 size_t buf_size
, nread
, psize
, dsize
;
141 struct ptable_ent
*pp
;
142 struct iso_directory_record
*dp
= 0;
145 /* First find the volume descriptor */
146 buf_size
= ISO_DEFAULT_BLOCK_SIZE
;
147 buf
= alloc(buf_size
);
149 for (bno
= 16;; bno
++) {
150 #if !defined(LIBSA_NO_TWIDDLE)
153 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
, cdb2devb(bno
),
154 ISO_DEFAULT_BLOCK_SIZE
, buf
, &nread
);
157 if (nread
!= ISO_DEFAULT_BLOCK_SIZE
) {
162 if (memcmp(vd
->id
, ISO_STANDARD_ID
, sizeof vd
->id
) != 0)
164 if (isonum_711(vd
->type
) == ISO_VD_END
)
166 if (isonum_711(vd
->type
) == ISO_VD_PRIMARY
)
169 if (isonum_723(vd
->logical_block_size
) != ISO_DEFAULT_BLOCK_SIZE
)
172 /* Now get the path table and lookup the directory of the file */
173 bno
= isonum_732(vd
->type_m_path_table
);
174 psize
= isonum_733(vd
->path_table_size
);
176 if (psize
> ISO_DEFAULT_BLOCK_SIZE
) {
177 dealloc(buf
, ISO_DEFAULT_BLOCK_SIZE
);
178 buf
= alloc(buf_size
= roundup(psize
, ISO_DEFAULT_BLOCK_SIZE
));
181 #if !defined(LIBSA_NO_TWIDDLE)
184 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
, cdb2devb(bno
),
185 buf_size
, buf
, &nread
);
188 if (nread
!= buf_size
) {
194 pp
= (struct ptable_ent
*)buf
;
196 bno
= isonum_732(pp
->block
) + isonum_711(pp
->extlen
);
200 * Remove extra separators
206 if ((char *)pp
>= (char *)buf
+ psize
)
208 if (isonum_722(pp
->parent
) != parent
)
210 if (!pnmatch(path
, pp
)) {
211 pp
= (struct ptable_ent
*)((char *)pp
+ PTSIZE(pp
));
215 path
+= isonum_711(pp
->namlen
) + 1;
217 bno
= isonum_732(pp
->block
) + isonum_711(pp
->extlen
);
218 while ((char *)pp
< (char *)buf
+ psize
) {
219 if (isonum_722(pp
->parent
) == parent
)
221 pp
= (struct ptable_ent
*)((char *)pp
+ PTSIZE(pp
));
227 * Now bno has the start of the directory that supposedly
231 dsize
= 1; /* Something stupid, but > 0 XXX */
232 for (psize
= 0; psize
< dsize
;) {
233 if (!(psize
% ISO_DEFAULT_BLOCK_SIZE
)) {
235 #if !defined(LIBSA_NO_TWIDDLE)
238 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
,
240 ISO_DEFAULT_BLOCK_SIZE
,
244 if (nread
!= ISO_DEFAULT_BLOCK_SIZE
) {
248 dp
= (struct iso_directory_record
*)buf
;
250 if (!isonum_711(dp
->length
)) {
251 if ((void *)dp
== buf
)
252 psize
+= ISO_DEFAULT_BLOCK_SIZE
;
254 psize
= roundup(psize
, ISO_DEFAULT_BLOCK_SIZE
);
258 dsize
= isonum_733(dp
->size
);
259 if (dirmatch(path
, dp
))
261 psize
+= isonum_711(dp
->length
);
262 dp
= (struct iso_directory_record
*)
263 ((char *)dp
+ isonum_711(dp
->length
));
266 if (psize
>= dsize
) {
271 /* allocate file system specific data structure */
272 fp
= alloc(sizeof(struct file
));
273 memset(fp
, 0, sizeof(struct file
));
274 f
->f_fsdata
= (void *)fp
;
277 fp
->bno
= isonum_733(dp
->extent
);
278 fp
->size
= isonum_733(dp
->size
);
279 dealloc(buf
, buf_size
);
286 dealloc(fp
, sizeof(struct file
));
287 dealloc(buf
, buf_size
);
292 #if !defined(LIBSA_NO_FS_CLOSE)
294 cd9660_close(struct open_file
*f
)
296 struct file
*fp
= (struct file
*)f
->f_fsdata
;
299 dealloc(fp
, sizeof *fp
);
303 #endif /* !defined(LIBSA_NO_FS_CLOSE) */
306 cd9660_read(struct open_file
*f
, void *start
, size_t size
, size_t *resid
)
308 struct file
*fp
= (struct file
*)f
->f_fsdata
;
311 char buf
[ISO_DEFAULT_BLOCK_SIZE
];
316 if (fp
->off
< 0 || fp
->off
>= fp
->size
)
318 bno
= fp
->off
/ ISO_DEFAULT_BLOCK_SIZE
+ fp
->bno
;
319 if (fp
->off
& (ISO_DEFAULT_BLOCK_SIZE
- 1)
320 || size
< ISO_DEFAULT_BLOCK_SIZE
)
324 #if !defined(LIBSA_NO_TWIDDLE)
327 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
, cdb2devb(bno
),
328 ISO_DEFAULT_BLOCK_SIZE
, dp
, &nread
);
331 if (nread
!= ISO_DEFAULT_BLOCK_SIZE
)
334 off
= fp
->off
& (ISO_DEFAULT_BLOCK_SIZE
- 1);
335 if (nread
> off
+ size
)
338 memcpy(start
, buf
+ off
, nread
);
339 start
= (char *)start
+ nread
;
343 start
= (char *)start
+ ISO_DEFAULT_BLOCK_SIZE
;
344 fp
->off
+= ISO_DEFAULT_BLOCK_SIZE
;
345 size
-= ISO_DEFAULT_BLOCK_SIZE
;
353 #if !defined(LIBSA_NO_FS_WRITE)
355 cd9660_write(struct open_file
*f
, void *start
, size_t size
, size_t *resid
)
360 #endif /* !defined(LIBSA_NO_FS_WRITE) */
362 #if !defined(LIBSA_NO_FS_SEEK)
364 cd9660_seek(struct open_file
*f
, off_t offset
, int where
)
366 struct file
*fp
= (struct file
*)f
->f_fsdata
;
376 fp
->off
= fp
->size
- offset
;
383 #endif /* !defined(LIBSA_NO_FS_SEEK) */
386 cd9660_stat(struct open_file
*f
, struct stat
*sb
)
388 struct file
*fp
= (struct file
*)f
->f_fsdata
;
390 /* only importatn stuff */
391 sb
->st_mode
= S_IFREG
| S_IRUSR
| S_IRGRP
| S_IROTH
;
392 sb
->st_uid
= sb
->st_gid
= 0;
393 sb
->st_size
= fp
->size
;