1 /* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */
3 * fsw_iso9660.c - ISO9660 file system driver code.
6 * - Files must be in one extent (i.e. Level 2)
7 * - No Joliet or Rock Ridge extensions
9 * - inode number generation strategy fails on volumes > 2 GB
10 * - No blocksizes != 2048
11 * - No High Sierra or anything else != 'CD001'
12 * - No volume sets with directories pointing at other volumes
13 * - No extended attribute records
17 * Copyright (C) 2010 Oracle Corporation
19 * This file is part of VirtualBox Open Source Edition (OSE), as
20 * available from http://www.virtualbox.org. This file is free software;
21 * you can redistribute it and/or modify it under the terms of the GNU
22 * General Public License (GPL) as published by the Free Software
23 * Foundation, in version 2 as it comes in the "COPYING" file of the
24 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
25 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
29 * This code is based on:
31 * Copyright (c) 2006 Christoph Pfisterer
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are
37 * * Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
40 * * Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the
45 * * Neither the name of Christoph Pfisterer nor the names of the
46 * contributors may be used to endorse or promote products derived
47 * from this software without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 #include "fsw_iso9660.h"
63 //#include <Protocol/MsgLog.h>
70 #define DBG(x...) AsciiPrint(x)
72 #define DBG(x...) BootLog(x)
77 //#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}}
79 // extern CHAR8 *msgCursor;
80 // extern MESSAGE_LOG_PROTOCOL *Msg;
83 static fsw_status_t
fsw_iso9660_volume_mount(struct fsw_iso9660_volume
*vol
);
84 static void fsw_iso9660_volume_free(struct fsw_iso9660_volume
*vol
);
85 static fsw_status_t
fsw_iso9660_volume_stat(struct fsw_iso9660_volume
*vol
, struct fsw_volume_stat
*sb
);
87 static fsw_status_t
fsw_iso9660_dnode_fill(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
);
88 static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
);
89 static fsw_status_t
fsw_iso9660_dnode_stat(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
90 struct fsw_dnode_stat
*sb
);
91 static fsw_status_t
fsw_iso9660_get_extent(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
92 struct fsw_extent
*extent
);
94 static fsw_status_t
fsw_iso9660_dir_lookup(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
95 struct fsw_string
*lookup_name
, struct fsw_iso9660_dnode
**child_dno
);
96 static fsw_status_t
fsw_iso9660_dir_read(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
97 struct fsw_shandle
*shand
, struct fsw_iso9660_dnode
**child_dno
);
98 static fsw_status_t
fsw_iso9660_read_dirrec(struct fsw_iso9660_volume
*vol
, struct fsw_shandle
*shand
, struct iso9660_dirrec_buffer
*dirrec_buffer
);
100 static fsw_status_t
fsw_iso9660_readlink(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
101 struct fsw_string
*link
);
103 static fsw_status_t
rr_find_sp(struct iso9660_dirrec
*dirrec
, struct fsw_rock_ridge_susp_sp
**psp
);
104 static fsw_status_t
rr_find_nm(struct fsw_iso9660_volume
*vol
, struct iso9660_dirrec
*dirrec
, int off
, struct fsw_string
*str
);
105 static fsw_status_t
rr_read_ce(struct fsw_iso9660_volume
*vol
, union fsw_rock_ridge_susp_ce
*ce
, fsw_u8
*begin
);
106 //static void dump_dirrec(struct iso9660_dirrec *dirrec);
111 struct fsw_fstype_table
FSW_FSTYPE_TABLE_NAME(iso9660
) = {
112 { FSW_STRING_TYPE_ISO88591
, 4, 4, "iso9660" },
113 sizeof(struct fsw_iso9660_volume
),
114 sizeof(struct fsw_iso9660_dnode
),
116 fsw_iso9660_volume_mount
,
117 fsw_iso9660_volume_free
,
118 fsw_iso9660_volume_stat
,
119 fsw_iso9660_dnode_fill
,
120 fsw_iso9660_dnode_free
,
121 fsw_iso9660_dnode_stat
,
122 fsw_iso9660_get_extent
,
123 fsw_iso9660_dir_lookup
,
124 fsw_iso9660_dir_read
,
125 fsw_iso9660_readlink
,
128 static fsw_status_t
rr_find_sp(struct iso9660_dirrec
*dirrec
, struct fsw_rock_ridge_susp_sp
**psp
)
132 struct fsw_rock_ridge_susp_sp
*sp
;
133 r
= (fsw_u8
*)((fsw_u8
*)dirrec
+ sizeof(*dirrec
) + dirrec
->file_identifier_length
);
134 off
= (int)(r
- (fsw_u8
*)dirrec
);
135 while(off
< dirrec
->dirrec_length
)
139 sp
= (struct fsw_rock_ridge_susp_sp
*)r
;
140 if( sp
->e
.sig
[0] == 'S'
141 && sp
->e
.sig
[1] == 'P'
142 && sp
->magic
[0] == 0xbe
143 && sp
->magic
[1] == 0xef)
150 off
= (int)(r
- (fsw_u8
*)dirrec
);
153 return FSW_NOT_FOUND
;
156 static fsw_status_t
rr_find_nm(struct fsw_iso9660_volume
*vol
, struct iso9660_dirrec
*dirrec
, int off
, struct fsw_string
*str
)
160 struct fsw_rock_ridge_susp_nm
*nm
;
161 int limit
= dirrec
->dirrec_length
;
162 begin
= (fsw_u8
*)dirrec
;
163 r
= (fsw_u8
*)dirrec
+ off
;
170 if (r
[0] == 'C' && r
[1] == 'E' && r
[2] == 28)
174 union fsw_rock_ridge_susp_ce
*ce
;
176 fsw_alloc_zero(ISO9660_BLOCKSIZE
, (void *)&begin
);
178 // DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
179 ce
= (union fsw_rock_ridge_susp_ce
*)r
;
180 limit
= ISOINT(ce
->X
.len
);
181 ce_off
= ISOINT(ce
->X
.offset
);
182 rc
= rr_read_ce(vol
, ce
, begin
);
183 if (rc
!= FSW_SUCCESS
)
191 if (r
[0] == 'N' && r
[1] == 'M')
193 nm
= (struct fsw_rock_ridge_susp_nm
*)r
;
194 if( nm
->e
.sig
[0] == 'N'
195 && nm
->e
.sig
[1] == 'M')
199 if (nm
->flags
& RR_NM_CURR
)
201 fsw_memdup(str
->data
, ".", 1);
205 if (nm
->flags
& RR_NM_PARE
)
207 fsw_memdup(str
->data
, "..", 2);
211 len
= nm
->e
.len
- sizeof(struct fsw_rock_ridge_susp_nm
) + 1;
212 fsw_alloc_zero(str
->len
+ len
, (void **)&tmp
);
213 if (str
->data
!= NULL
)
215 fsw_memcpy(tmp
, str
->data
, str
->len
);
218 // DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
219 fsw_memcpy(tmp
+ str
->len
, &nm
->name
[0], len
);
223 if ((nm
->flags
& RR_NM_CONT
) == 0);
228 off
= (int)(r
- (fsw_u8
*)begin
);
232 return FSW_NOT_FOUND
;
234 str
->type
= FSW_STRING_TYPE_ISO88591
;
235 str
->size
= str
->len
;
241 static fsw_status_t
rr_read_ce(struct fsw_iso9660_volume
*vol
, union fsw_rock_ridge_susp_ce
*ce
, fsw_u8
*begin
)
245 // fsw_u8 *r = begin + ISOINT(ce->X.offset);
246 // int len = ISOINT(ce->X.len);
247 rc
= vol
->g
.host_table
->read_block(&vol
->g
, ISOINT(ce
->X
.block_loc
), begin
);
248 if (rc
!= FSW_SUCCESS
)
250 /* for (i = 0; i < len; ++i)
252 DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
257 static void dump_dirrec(struct iso9660_dirrec *dirrec)
260 fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length;
261 int len = dirrec->dirrec_length;
262 for (i = dirrec->file_identifier_length; i < len; ++i)
264 DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
268 * Mount an ISO9660 volume. Reads the superblock and constructs the
269 * root directory dnode.
272 static fsw_status_t
fsw_iso9660_volume_mount(struct fsw_iso9660_volume
*vol
)
277 struct iso9660_volume_descriptor
*voldesc
;
278 struct iso9660_primary_volume_descriptor
*pvoldesc
;
279 fsw_u32 voldesc_type
;
282 struct iso9660_dirrec rootdir
;
285 struct fsw_rock_ridge_susp_entry
*entry
;
287 // read through the Volume Descriptor Set
288 fsw_set_blocksize(vol
, ISO9660_BLOCKSIZE
, ISO9660_BLOCKSIZE
);
289 blockno
= ISO9660_SUPERBLOCK_BLOCKNO
;
292 // DBG("iso9660: check blockno=%d\n", blockno);
293 status
= fsw_block_get(vol
, blockno
, 0, &buffer
);
297 voldesc
= (struct iso9660_volume_descriptor
*)buffer
;
298 voldesc_type
= voldesc
->volume_descriptor_type
;
299 if (fsw_memeq(voldesc
->standard_identifier
, "CD001", 5)) {
300 // descriptor follows ISO 9660 standard
301 if (voldesc_type
== 1 && voldesc
->volume_descriptor_version
== 1) {
302 // suitable Primary Volume Descriptor found
303 // DBG("iso9660: suitable Primary Volume Descriptor found\n");
304 if (vol
->primary_voldesc
) {
305 fsw_free(vol
->primary_voldesc
);
306 vol
->primary_voldesc
= NULL
;
308 status
= fsw_memdup((void **)&vol
->primary_voldesc
, voldesc
, ISO9660_BLOCKSIZE
);
310 } else if (!fsw_memeq(voldesc
->standard_identifier
, "CD", 2)) {
311 // completely alien standard identifier, stop reading
315 fsw_block_release(vol
, blockno
, buffer
);
317 } while (!status
&& voldesc_type
!= 255);
321 // get information from Primary Volume Descriptor
322 if (vol
->primary_voldesc
== NULL
)
323 return FSW_UNSUPPORTED
;
324 pvoldesc
= vol
->primary_voldesc
;
325 // if (ISOINT(pvoldesc->logical_block_size) != 2048)
326 // return FSW_UNSUPPORTED;
329 for (i
= 32; i
> 0; i
--)
330 if (pvoldesc
->volume_identifier
[i
-1] != ' ')
332 s
.type
= FSW_STRING_TYPE_ISO88591
;
334 s
.data
= pvoldesc
->volume_identifier
;
335 status
= fsw_strdup_coerce(&vol
->g
.label
, vol
->g
.host_string_type
, &s
);
339 // setup the root dnode
340 status
= fsw_dnode_create_root(vol
, ISO9660_SUPERBLOCK_BLOCKNO
<< ISO9660_BLOCKSIZE_BITS
, &vol
->g
.root
);
343 fsw_memcpy(&vol
->g
.root
->dirrec
, &pvoldesc
->root_directory
, sizeof(struct iso9660_dirrec
));
345 if ( pvoldesc
->escape
[0] == 0x25
346 && pvoldesc
->escape
[1] == 0x2f
347 && ( pvoldesc
->escape
[2] == 0x40
348 || pvoldesc
->escape
[2] == 0x43
349 || pvoldesc
->escape
[2] == 0x45))
351 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
352 // DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n");
357 rootdir
= pvoldesc
->root_directory
;
358 sua_pos
= (sizeof(struct iso9660_dirrec
)) + rootdir
.file_identifier_length
+ (rootdir
.file_identifier_length
% 2) - 2;
359 //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
360 //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
363 status
= fsw_block_get(vol
, ISOINT(rootdir
.extent_location
), 0, &buffer
);
364 sig
= (char *)buffer
+ sua_pos
;
365 entry
= (struct fsw_rock_ridge_susp_entry
*)sig
;
366 if ( entry
->sig
[0] == 'S'
367 && entry
->sig
[1] == 'P')
369 struct fsw_rock_ridge_susp_sp
*sp
= (struct fsw_rock_ridge_susp_sp
*)entry
;
370 if (sp
->magic
[0] == 0xbe && sp
->magic
[1] == 0xef)
374 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
375 // DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n");
379 // release volume descriptors
380 fsw_free(vol
->primary_voldesc
);
381 vol
->primary_voldesc
= NULL
;
384 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
385 // DBG("fsw_iso9660_volume_mount: success\n");
391 * Free the volume data structure. Called by the core after an unmount or after
392 * an unsuccessful mount to release the memory used by the file system type specific
393 * part of the volume structure.
396 static void fsw_iso9660_volume_free(struct fsw_iso9660_volume
*vol
)
398 if (vol
->primary_voldesc
)
399 fsw_free(vol
->primary_voldesc
);
403 * Get in-depth information on a volume.
406 static fsw_status_t
fsw_iso9660_volume_stat(struct fsw_iso9660_volume
*vol
, struct fsw_volume_stat
*sb
)
408 sb
->total_bytes
= 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
414 * Get full information on a dnode from disk. This function is called by the core
415 * whenever it needs to access fields in the dnode structure that may not
416 * be filled immediately upon creation of the dnode. In the case of iso9660, we
417 * delay fetching of the inode structure until dnode_fill is called. The size and
418 * type fields are invalid until this function has been called.
421 static fsw_status_t
fsw_iso9660_dnode_fill(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
)
423 // get info from the directory record
424 dno
->g
.size
= ISOINT(dno
->dirrec
.data_length
);
425 if (dno
->dirrec
.file_flags
& 0x02)
426 dno
->g
.type
= FSW_DNODE_TYPE_DIR
;
428 dno
->g
.type
= FSW_DNODE_TYPE_FILE
;
434 * Free the dnode data structure. Called by the core when deallocating a dnode
435 * structure to release the memory used by the file system type specific part
436 * of the dnode structure.
439 static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
)
444 * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
445 * has been called on the dnode before this function is called. Note that some
446 * data is not directly stored into the structure, but passed to a host-specific
447 * callback that converts it to the host-specific format.
450 static fsw_status_t
fsw_iso9660_dnode_stat(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
451 struct fsw_dnode_stat
*sb
)
453 sb
->used_bytes
= (dno
->g
.size
+ (ISO9660_BLOCKSIZE
-1)) & ~(ISO9660_BLOCKSIZE
-1);
455 sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
456 sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
457 sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
458 sb->store_attr_posix(sb, dno->raw->i_mode);
465 * Retrieve file data mapping information. This function is called by the core when
466 * fsw_shandle_read needs to know where on the disk the required piece of the file's
467 * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
468 * on the dnode before. Our task here is to get the physical disk block number for
469 * the requested logical block number.
472 static fsw_status_t
fsw_iso9660_get_extent(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
473 struct fsw_extent
*extent
)
475 // Preconditions: The caller has checked that the requested logical block
476 // is within the file's size. The dnode has complete information, i.e.
477 // fsw_iso9660_dnode_read_info was called successfully on it.
479 extent
->type
= FSW_EXTENT_TYPE_PHYSBLOCK
;
480 extent
->phys_start
= ISOINT(dno
->dirrec
.extent_location
);
481 extent
->log_start
= 0;
482 extent
->log_count
= (ISOINT(dno
->dirrec
.data_length
) + (ISO9660_BLOCKSIZE
-1)) >> ISO9660_BLOCKSIZE_BITS
;
487 * Lookup a directory's child dnode by name. This function is called on a directory
488 * to retrieve the directory entry with the given name. A dnode is constructed for
489 * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
490 * and the dnode is actually a directory.
493 static fsw_status_t
fsw_iso9660_dir_lookup(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
494 struct fsw_string
*lookup_name
, struct fsw_iso9660_dnode
**child_dno_out
)
497 struct fsw_shandle shand
;
498 struct iso9660_dirrec_buffer dirrec_buffer
;
499 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
.dirrec
;
501 // Preconditions: The caller has checked that dno is a directory node.
503 // setup handle to read the directory
504 status
= fsw_shandle_open(dno
, &shand
);
508 // scan the directory for the file
511 status
= fsw_iso9660_read_dirrec(vol
, &shand
, &dirrec_buffer
);
514 if (dirrec
->dirrec_length
== 0) {
515 // end of directory reached
516 status
= FSW_NOT_FOUND
;
521 if (dirrec
->file_identifier_length
== 1 &&
522 (dirrec
->file_identifier
[0] == 0 || dirrec
->file_identifier
[0] == 1))
526 if (fsw_streq(lookup_name
, &dirrec_buffer
.name
)) // TODO: compare case-insensitively
530 // setup a dnode for the child item
531 status
= fsw_dnode_create(dno
, dirrec_buffer
.ino
, FSW_DNODE_TYPE_UNKNOWN
, &dirrec_buffer
.name
, child_dno_out
);
532 if (status
== FSW_SUCCESS
)
533 fsw_memcpy(&(*child_dno_out
)->dirrec
, dirrec
, sizeof(struct iso9660_dirrec
));
536 fsw_shandle_close(&shand
);
541 * Get the next directory entry when reading a directory. This function is called during
542 * directory iteration to retrieve the next directory entry. A dnode is constructed for
543 * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
544 * and the dnode is actually a directory. The shandle provided by the caller is used to
545 * record the position in the directory between calls.
548 static fsw_status_t
fsw_iso9660_dir_read(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
549 struct fsw_shandle
*shand
, struct fsw_iso9660_dnode
**child_dno_out
)
552 struct iso9660_dirrec_buffer dirrec_buffer
;
553 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
.dirrec
;
555 // Preconditions: The caller has checked that dno is a directory node. The caller
556 // has opened a storage handle to the directory's storage and keeps it around between
558 /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
559 * should read both blocks.
564 if (shand
->pos
>= dno
->g
.size
)
565 return FSW_NOT_FOUND
; // end of directory
566 status
= fsw_iso9660_read_dirrec(vol
, shand
, &dirrec_buffer
);
569 if (dirrec
->dirrec_length
== 0)
571 // try the next block
572 shand
->pos
=(shand
->pos
& ~(vol
->g
.log_blocksize
- 1)) + vol
->g
.log_blocksize
;
577 if (dirrec
->file_identifier_length
== 1 &&
578 (dirrec
->file_identifier
[0] == 0 || dirrec
->file_identifier
[0] == 1))
583 // setup a dnode for the child item
584 status
= fsw_dnode_create(dno
, dirrec_buffer
.ino
, FSW_DNODE_TYPE_UNKNOWN
, &dirrec_buffer
.name
, child_dno_out
);
585 if (status
== FSW_SUCCESS
)
586 fsw_memcpy(&(*child_dno_out
)->dirrec
, dirrec
, sizeof(struct iso9660_dirrec
));
592 * Read a directory entry from the directory's raw data. This internal function is used
593 * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
594 * to point to the next entry.
597 static fsw_status_t
fsw_iso9660_read_dirrec(struct fsw_iso9660_volume
*vol
, struct fsw_shandle
*shand
, struct iso9660_dirrec_buffer
*dirrec_buffer
)
600 fsw_u32 i
, buffer_size
, remaining_size
, name_len
;
601 struct fsw_rock_ridge_susp_sp
*sp
= NULL
;
602 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
->dirrec
;
606 dirrec_buffer
->ino
= (ISOINT(((struct fsw_iso9660_dnode
*)shand
->dnode
)->dirrec
.extent_location
)
607 << ISO9660_BLOCKSIZE_BITS
)
608 + (fsw_u32
)shand
->pos
;
610 // read fixed size part of directory record
612 status
= fsw_shandle_read(shand
, &buffer_size
, dirrec
);
615 // DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
619 if (buffer_size
< 33 || dirrec
->dirrec_length
== 0) {
620 // end of directory reached
622 r
= (fsw_u8
*)dirrec
;
623 // DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
624 for(i
= 0; i
< buffer_size
; ++i
)
626 DEBUG((DEBUG_INFO
, "r[%d]:%c", i
, r
[i
]));
628 dirrec
->dirrec_length
= 0;
631 if (dirrec
->dirrec_length
< 33 ||
632 dirrec
->dirrec_length
< 33 + dirrec
->file_identifier_length
)
633 return FSW_VOLUME_CORRUPTED
;
635 // DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
637 // read variable size part of directory record
638 buffer_size
= remaining_size
= dirrec
->dirrec_length
- 33;
639 status
= fsw_shandle_read(shand
, &buffer_size
, dirrec
->file_identifier
);
642 if (buffer_size
< remaining_size
)
643 return FSW_VOLUME_CORRUPTED
;
645 // dump_dirrec(dirrec);
648 sp_off
= sizeof(*dirrec
) + dirrec
->file_identifier_length
;
649 rc
= rr_find_sp(dirrec
, &sp
);
650 if ( rc
== FSW_SUCCESS
653 sp_off
= (fsw_u8
*)&sp
[1] - (fsw_u8
*)dirrec
+ sp
->skip
;
655 rc
= rr_find_nm(vol
, dirrec
, sp_off
, &dirrec_buffer
->name
);
656 if (rc
== FSW_SUCCESS
)
661 name_len
= dirrec
->file_identifier_length
;
662 for (i
= name_len
- 1; i
> 0; i
--) {
663 if (dirrec
->file_identifier
[i
] == ';') {
664 name_len
= i
; // cut the ISO9660 version number off
668 if (name_len
> 0 && dirrec
->file_identifier
[name_len
-1] == '.')
669 name_len
--; // also cut the extension separator if the extension is empty
670 dirrec_buffer
->name
.type
= FSW_STRING_TYPE_ISO88591
;
671 dirrec_buffer
->name
.len
= dirrec_buffer
->name
.size
= name_len
;
672 dirrec_buffer
->name
.data
= dirrec
->file_identifier
;
673 // DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
678 * Get the target path of a symbolic link. This function is called when a symbolic
679 * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
680 * called on the dnode and that it really is a symlink.
682 * For iso9660, the target path can be stored inline in the inode structure (in the space
683 * otherwise occupied by the block pointers) or in the inode's data. There is no flag
684 * indicating this, only the number of blocks entry (i_blocks) can be used as an
685 * indication. The check used here comes from the Linux kernel.
688 static fsw_status_t
fsw_iso9660_readlink(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
689 struct fsw_string
*link_target
)
693 if (dno
->g
.size
> FSW_PATH_MAX
)
694 return FSW_VOLUME_CORRUPTED
;
696 status
= fsw_dnode_readlink_data(dno
, link_target
);