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
;
286 struct fsw_rock_ridge_susp_entry
*entry
;
288 // read through the Volume Descriptor Set
289 fsw_set_blocksize(vol
, ISO9660_BLOCKSIZE
, ISO9660_BLOCKSIZE
);
290 blockno
= ISO9660_SUPERBLOCK_BLOCKNO
;
293 // DBG("iso9660: check blockno=%d\n", blockno);
294 status
= fsw_block_get(vol
, blockno
, 0, &buffer
);
298 voldesc
= (struct iso9660_volume_descriptor
*)buffer
;
299 voldesc_type
= voldesc
->volume_descriptor_type
;
300 if (fsw_memeq(voldesc
->standard_identifier
, "CD001", 5)) {
301 // descriptor follows ISO 9660 standard
302 if (voldesc_type
== 1 && voldesc
->volume_descriptor_version
== 1) {
303 // suitable Primary Volume Descriptor found
304 // DBG("iso9660: suitable Primary Volume Descriptor found\n");
305 if (vol
->primary_voldesc
) {
306 fsw_free(vol
->primary_voldesc
);
307 vol
->primary_voldesc
= NULL
;
309 status
= fsw_memdup((void **)&vol
->primary_voldesc
, voldesc
, ISO9660_BLOCKSIZE
);
311 } else if (!fsw_memeq(voldesc
->standard_identifier
, "CD", 2)) {
312 // completely alien standard identifier, stop reading
316 fsw_block_release(vol
, blockno
, buffer
);
318 } while (!status
&& voldesc_type
!= 255);
322 // get information from Primary Volume Descriptor
323 if (vol
->primary_voldesc
== NULL
)
324 return FSW_UNSUPPORTED
;
325 pvoldesc
= vol
->primary_voldesc
;
326 if (ISOINT(pvoldesc
->logical_block_size
) != 2048)
327 return FSW_UNSUPPORTED
;
330 for (i
= 32; i
> 0; i
--)
331 if (pvoldesc
->volume_identifier
[i
-1] != ' ')
333 s
.type
= FSW_STRING_TYPE_ISO88591
;
335 s
.data
= pvoldesc
->volume_identifier
;
336 status
= fsw_strdup_coerce(&vol
->g
.label
, vol
->g
.host_string_type
, &s
);
340 // setup the root dnode
341 status
= fsw_dnode_create_root(vol
, ISO9660_SUPERBLOCK_BLOCKNO
<< ISO9660_BLOCKSIZE_BITS
, &vol
->g
.root
);
344 fsw_memcpy(&vol
->g
.root
->dirrec
, &pvoldesc
->root_directory
, sizeof(struct iso9660_dirrec
));
346 if ( pvoldesc
->escape
[0] == 0x25
347 && pvoldesc
->escape
[1] == 0x2f
348 && ( pvoldesc
->escape
[2] == 0x40
349 || pvoldesc
->escape
[2] == 0x43
350 || pvoldesc
->escape
[2] == 0x45))
352 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
353 // DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n");
358 rootdir
= pvoldesc
->root_directory
;
359 sua_pos
= (sizeof(struct iso9660_dirrec
)) + rootdir
.file_identifier_length
+ (rootdir
.file_identifier_length
% 2) - 2;
360 //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
361 //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
364 status
= fsw_block_get(vol
, ISOINT(rootdir
.extent_location
), 0, &buffer
);
365 sig
= (char *)buffer
+ sua_pos
;
367 entry
= (struct fsw_rock_ridge_susp_entry
*)sig
;
368 if ( entry
->sig
[0] == 'S'
369 && entry
->sig
[1] == 'P')
371 struct fsw_rock_ridge_susp_sp
*sp
= (struct fsw_rock_ridge_susp_sp
*)entry
;
372 if (sp
->magic
[0] == 0xbe && sp
->magic
[1] == 0xef)
376 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
377 // DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n");
382 // release volume descriptors
383 fsw_free(vol
->primary_voldesc
);
384 vol
->primary_voldesc
= NULL
;
387 // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
388 // DBG("fsw_iso9660_volume_mount: success\n");
394 * Free the volume data structure. Called by the core after an unmount or after
395 * an unsuccessful mount to release the memory used by the file system type specific
396 * part of the volume structure.
399 static void fsw_iso9660_volume_free(struct fsw_iso9660_volume
*vol
)
401 if (vol
->primary_voldesc
)
402 fsw_free(vol
->primary_voldesc
);
406 * Get in-depth information on a volume.
409 static fsw_status_t
fsw_iso9660_volume_stat(struct fsw_iso9660_volume
*vol
, struct fsw_volume_stat
*sb
)
411 sb
->total_bytes
= 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
417 * Get full information on a dnode from disk. This function is called by the core
418 * whenever it needs to access fields in the dnode structure that may not
419 * be filled immediately upon creation of the dnode. In the case of iso9660, we
420 * delay fetching of the inode structure until dnode_fill is called. The size and
421 * type fields are invalid until this function has been called.
424 static fsw_status_t
fsw_iso9660_dnode_fill(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
)
426 // get info from the directory record
427 dno
->g
.size
= ISOINT(dno
->dirrec
.data_length
);
428 if (dno
->dirrec
.file_flags
& 0x02)
429 dno
->g
.type
= FSW_DNODE_TYPE_DIR
;
431 dno
->g
.type
= FSW_DNODE_TYPE_FILE
;
437 * Free the dnode data structure. Called by the core when deallocating a dnode
438 * structure to release the memory used by the file system type specific part
439 * of the dnode structure.
442 static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
)
447 * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
448 * has been called on the dnode before this function is called. Note that some
449 * data is not directly stored into the structure, but passed to a host-specific
450 * callback that converts it to the host-specific format.
453 static fsw_status_t
fsw_iso9660_dnode_stat(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
454 struct fsw_dnode_stat
*sb
)
456 sb
->used_bytes
= (dno
->g
.size
+ (ISO9660_BLOCKSIZE
-1)) & ~(ISO9660_BLOCKSIZE
-1);
458 sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
459 sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
460 sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
461 sb->store_attr_posix(sb, dno->raw->i_mode);
468 * Retrieve file data mapping information. This function is called by the core when
469 * fsw_shandle_read needs to know where on the disk the required piece of the file's
470 * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
471 * on the dnode before. Our task here is to get the physical disk block number for
472 * the requested logical block number.
475 static fsw_status_t
fsw_iso9660_get_extent(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
476 struct fsw_extent
*extent
)
478 // Preconditions: The caller has checked that the requested logical block
479 // is within the file's size. The dnode has complete information, i.e.
480 // fsw_iso9660_dnode_read_info was called successfully on it.
482 extent
->type
= FSW_EXTENT_TYPE_PHYSBLOCK
;
483 extent
->phys_start
= ISOINT(dno
->dirrec
.extent_location
);
484 extent
->log_start
= 0;
485 extent
->log_count
= (ISOINT(dno
->dirrec
.data_length
) + (ISO9660_BLOCKSIZE
-1)) >> ISO9660_BLOCKSIZE_BITS
;
490 * Lookup a directory's child dnode by name. This function is called on a directory
491 * to retrieve the directory entry with the given name. A dnode is constructed for
492 * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
493 * and the dnode is actually a directory.
496 static fsw_status_t
fsw_iso9660_dir_lookup(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
497 struct fsw_string
*lookup_name
, struct fsw_iso9660_dnode
**child_dno_out
)
500 struct fsw_shandle shand
;
501 struct iso9660_dirrec_buffer dirrec_buffer
;
502 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
.dirrec
;
504 // Preconditions: The caller has checked that dno is a directory node.
506 // setup handle to read the directory
507 status
= fsw_shandle_open(dno
, &shand
);
511 // scan the directory for the file
514 status
= fsw_iso9660_read_dirrec(vol
, &shand
, &dirrec_buffer
);
517 if (dirrec
->dirrec_length
== 0) {
518 // end of directory reached
519 status
= FSW_NOT_FOUND
;
524 if (dirrec
->file_identifier_length
== 1 &&
525 (dirrec
->file_identifier
[0] == 0 || dirrec
->file_identifier
[0] == 1))
529 if (fsw_streq(lookup_name
, &dirrec_buffer
.name
)) // TODO: compare case-insensitively
533 // setup a dnode for the child item
534 status
= fsw_dnode_create(dno
, dirrec_buffer
.ino
, FSW_DNODE_TYPE_UNKNOWN
, &dirrec_buffer
.name
, child_dno_out
);
535 if (status
== FSW_SUCCESS
)
536 fsw_memcpy(&(*child_dno_out
)->dirrec
, dirrec
, sizeof(struct iso9660_dirrec
));
539 fsw_shandle_close(&shand
);
544 * Get the next directory entry when reading a directory. This function is called during
545 * directory iteration to retrieve the next directory entry. A dnode is constructed for
546 * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
547 * and the dnode is actually a directory. The shandle provided by the caller is used to
548 * record the position in the directory between calls.
551 static fsw_status_t
fsw_iso9660_dir_read(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
552 struct fsw_shandle
*shand
, struct fsw_iso9660_dnode
**child_dno_out
)
555 struct iso9660_dirrec_buffer dirrec_buffer
;
556 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
.dirrec
;
558 // Preconditions: The caller has checked that dno is a directory node. The caller
559 // has opened a storage handle to the directory's storage and keeps it around between
561 /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
562 * should read both blocks.
567 if (shand
->pos
>= dno
->g
.size
)
568 return FSW_NOT_FOUND
; // end of directory
569 status
= fsw_iso9660_read_dirrec(vol
, shand
, &dirrec_buffer
);
572 if (dirrec
->dirrec_length
== 0)
574 // try the next block
575 shand
->pos
=(shand
->pos
& ~(vol
->g
.log_blocksize
- 1)) + vol
->g
.log_blocksize
;
580 if (dirrec
->file_identifier_length
== 1 &&
581 (dirrec
->file_identifier
[0] == 0 || dirrec
->file_identifier
[0] == 1))
586 // setup a dnode for the child item
587 status
= fsw_dnode_create(dno
, dirrec_buffer
.ino
, FSW_DNODE_TYPE_UNKNOWN
, &dirrec_buffer
.name
, child_dno_out
);
588 if (status
== FSW_SUCCESS
)
589 fsw_memcpy(&(*child_dno_out
)->dirrec
, dirrec
, sizeof(struct iso9660_dirrec
));
595 * Read a directory entry from the directory's raw data. This internal function is used
596 * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
597 * to point to the next entry.
600 static fsw_status_t
fsw_iso9660_read_dirrec(struct fsw_iso9660_volume
*vol
, struct fsw_shandle
*shand
, struct iso9660_dirrec_buffer
*dirrec_buffer
)
603 fsw_u32 i
, buffer_size
, remaining_size
, name_len
;
604 struct fsw_rock_ridge_susp_sp
*sp
= NULL
;
605 struct iso9660_dirrec
*dirrec
= &dirrec_buffer
->dirrec
;
609 dirrec_buffer
->ino
= (ISOINT(((struct fsw_iso9660_dnode
*)shand
->dnode
)->dirrec
.extent_location
)
610 << ISO9660_BLOCKSIZE_BITS
)
611 + (fsw_u32
)shand
->pos
;
613 // read fixed size part of directory record
615 status
= fsw_shandle_read(shand
, &buffer_size
, dirrec
);
618 // DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
622 if (buffer_size
< 33 || dirrec
->dirrec_length
== 0) {
623 // end of directory reached
625 r
= (fsw_u8
*)dirrec
;
626 // DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
627 for(i
= 0; i
< buffer_size
; ++i
)
629 DEBUG((DEBUG_INFO
, "r[%d]:%c", i
, r
[i
]));
631 dirrec
->dirrec_length
= 0;
634 if (dirrec
->dirrec_length
< 33 ||
635 dirrec
->dirrec_length
< 33 + dirrec
->file_identifier_length
)
636 return FSW_VOLUME_CORRUPTED
;
638 // DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
640 // read variable size part of directory record
641 buffer_size
= remaining_size
= dirrec
->dirrec_length
- 33;
642 status
= fsw_shandle_read(shand
, &buffer_size
, dirrec
->file_identifier
);
645 if (buffer_size
< remaining_size
)
646 return FSW_VOLUME_CORRUPTED
;
648 // dump_dirrec(dirrec);
651 sp_off
= sizeof(*dirrec
) + dirrec
->file_identifier_length
;
652 rc
= rr_find_sp(dirrec
, &sp
);
653 if ( rc
== FSW_SUCCESS
656 sp_off
= (fsw_u8
*)&sp
[1] - (fsw_u8
*)dirrec
+ sp
->skip
;
658 rc
= rr_find_nm(vol
, dirrec
, sp_off
, &dirrec_buffer
->name
);
659 if (rc
== FSW_SUCCESS
)
664 name_len
= dirrec
->file_identifier_length
;
665 for (i
= name_len
- 1; i
> 0; i
--) {
666 if (dirrec
->file_identifier
[i
] == ';') {
667 name_len
= i
; // cut the ISO9660 version number off
671 if (name_len
> 0 && dirrec
->file_identifier
[name_len
-1] == '.')
672 name_len
--; // also cut the extension separator if the extension is empty
673 dirrec_buffer
->name
.type
= FSW_STRING_TYPE_ISO88591
;
674 dirrec_buffer
->name
.len
= dirrec_buffer
->name
.size
= name_len
;
675 dirrec_buffer
->name
.data
= dirrec
->file_identifier
;
676 // DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
681 * Get the target path of a symbolic link. This function is called when a symbolic
682 * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
683 * called on the dnode and that it really is a symlink.
685 * For iso9660, the target path can be stored inline in the inode structure (in the space
686 * otherwise occupied by the block pointers) or in the inode's data. There is no flag
687 * indicating this, only the number of blocks entry (i_blocks) can be used as an
688 * indication. The check used here comes from the Linux kernel.
691 static fsw_status_t
fsw_iso9660_readlink(struct fsw_iso9660_volume
*vol
, struct fsw_iso9660_dnode
*dno
,
692 struct fsw_string
*link_target
)
696 if (dno
->g
.size
> FSW_PATH_MAX
)
697 return FSW_VOLUME_CORRUPTED
;
699 status
= fsw_dnode_readlink_data(dno
, link_target
);