1 /* $NetBSD: cd9660.c,v 1.29 2012/07/23 00:49:20 mhitch 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
);
202 * Remove extra separators
207 if ((char *)pp
>= (char *)buf
+ psize
)
209 if (isonum_722(pp
->parent
) != parent
)
211 if (!pnmatch(path
, pp
)) {
212 pp
= (struct ptable_ent
*)((char *)pp
+ PTSIZE(pp
));
216 path
+= isonum_711(pp
->namlen
) + 1;
218 bno
= isonum_732(pp
->block
) + isonum_711(pp
->extlen
);
219 while ((char *)pp
< (char *)buf
+ psize
) {
220 if (isonum_722(pp
->parent
) == parent
)
222 pp
= (struct ptable_ent
*)((char *)pp
+ PTSIZE(pp
));
228 * Now bno has the start of the directory that supposedly
232 dsize
= 1; /* Something stupid, but > 0 XXX */
233 for (psize
= 0; psize
< dsize
;) {
234 if (!(psize
% ISO_DEFAULT_BLOCK_SIZE
)) {
236 #if !defined(LIBSA_NO_TWIDDLE)
239 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
,
241 ISO_DEFAULT_BLOCK_SIZE
,
245 if (nread
!= ISO_DEFAULT_BLOCK_SIZE
) {
249 dp
= (struct iso_directory_record
*)buf
;
251 if (!isonum_711(dp
->length
)) {
252 if ((void *)dp
== buf
)
253 psize
+= ISO_DEFAULT_BLOCK_SIZE
;
255 psize
= roundup(psize
, ISO_DEFAULT_BLOCK_SIZE
);
259 dsize
= isonum_733(dp
->size
);
260 if (dirmatch(path
, dp
))
262 psize
+= isonum_711(dp
->length
);
263 dp
= (struct iso_directory_record
*)
264 ((char *)dp
+ isonum_711(dp
->length
));
267 if (psize
>= dsize
) {
272 /* allocate file system specific data structure */
273 fp
= alloc(sizeof(struct file
));
274 memset(fp
, 0, sizeof(struct file
));
275 f
->f_fsdata
= (void *)fp
;
278 fp
->bno
= isonum_733(dp
->extent
);
279 fp
->size
= isonum_733(dp
->size
);
280 dealloc(buf
, buf_size
);
287 dealloc(fp
, sizeof(struct file
));
288 dealloc(buf
, buf_size
);
293 #if !defined(LIBSA_NO_FS_CLOSE)
295 cd9660_close(struct open_file
*f
)
297 struct file
*fp
= (struct file
*)f
->f_fsdata
;
300 dealloc(fp
, sizeof *fp
);
304 #endif /* !defined(LIBSA_NO_FS_CLOSE) */
307 cd9660_read(struct open_file
*f
, void *start
, size_t size
, size_t *resid
)
309 struct file
*fp
= (struct file
*)f
->f_fsdata
;
312 char buf
[ISO_DEFAULT_BLOCK_SIZE
];
317 if (fp
->off
< 0 || fp
->off
>= fp
->size
)
319 bno
= fp
->off
/ ISO_DEFAULT_BLOCK_SIZE
+ fp
->bno
;
320 if (fp
->off
& (ISO_DEFAULT_BLOCK_SIZE
- 1)
321 || (fp
->off
+ ISO_DEFAULT_BLOCK_SIZE
) > fp
->size
322 || size
< ISO_DEFAULT_BLOCK_SIZE
)
326 #if !defined(LIBSA_NO_TWIDDLE)
329 rc
= DEV_STRATEGY(f
->f_dev
)(f
->f_devdata
, F_READ
, cdb2devb(bno
),
330 ISO_DEFAULT_BLOCK_SIZE
, dp
, &nread
);
333 if (nread
!= ISO_DEFAULT_BLOCK_SIZE
)
336 off
= fp
->off
& (ISO_DEFAULT_BLOCK_SIZE
- 1);
337 if (nread
> off
+ size
)
340 if (nread
> fp
->size
- fp
->off
)
341 nread
= fp
->size
- fp
->off
;
342 memcpy(start
, buf
+ off
, nread
);
343 start
= (char *)start
+ nread
;
347 start
= (char *)start
+ ISO_DEFAULT_BLOCK_SIZE
;
348 fp
->off
+= ISO_DEFAULT_BLOCK_SIZE
;
349 size
-= ISO_DEFAULT_BLOCK_SIZE
;
352 if(fp
->off
> fp
->size
)
353 size
+= fp
->off
- fp
->size
;
359 #if !defined(LIBSA_NO_FS_WRITE)
361 cd9660_write(struct open_file
*f
, void *start
, size_t size
, size_t *resid
)
366 #endif /* !defined(LIBSA_NO_FS_WRITE) */
368 #if !defined(LIBSA_NO_FS_SEEK)
370 cd9660_seek(struct open_file
*f
, off_t offset
, int where
)
372 struct file
*fp
= (struct file
*)f
->f_fsdata
;
382 fp
->off
= fp
->size
- offset
;
389 #endif /* !defined(LIBSA_NO_FS_SEEK) */
392 cd9660_stat(struct open_file
*f
, struct stat
*sb
)
394 struct file
*fp
= (struct file
*)f
->f_fsdata
;
396 /* only importatn stuff */
397 sb
->st_mode
= S_IFREG
| S_IRUSR
| S_IRGRP
| S_IROTH
;
398 sb
->st_uid
= sb
->st_gid
= 0;
399 sb
->st_size
= fp
->size
;
403 #if defined(LIBSA_ENABLE_LS_OP)
405 cd9660_ls(struct open_file
*f
, const char *pattern
,
406 void (*funcp
)(char* arg
), char* path
)
408 printf("Currently ls command is unsupported by cd9660\n");