3 * Support for the ISO-9660 filing system.
5 * ----------------------------------------------------------------------
6 * This code is (C) Copyright 1993,1994 by Frank Munkert.
7 * (C) Copyright 2007-2010 The AROS Development Team.
9 * This software may be freely distributed and redistributed for
10 * non-commercial purposes, provided this notice is included.
11 * ----------------------------------------------------------------------
14 * 20-Apr-10 neil - Added work-around for Rock Ridge discs that have
15 * version numbers in file names.
16 * 10-Feb-10 neil - Removed error in fetching Rock Ridge names.
17 * 06-Mar-09 error - Removed madness, fixed insanity. Cleanup started
18 * 16-Jun-08 sonic - Skip files with "Associated" flag set. Helps to
19 * read ISO discs created under MacOS.
20 * - Supports "Hidden" flag.
21 * 06-May-07 sonic - Rewritten routines dealing with object names.
22 * - Added support for RockRidge protection bits and file comments.
23 * 08-Apr-07 sonic - removed redundant "TRACKDISK" option
24 * 31-Mar-07 sonic - added Joliet support.
25 * - removed static buffer in Get_Directory_Record().
26 * 20-Aug-94 fmu Uses function Find_Last_Session() before the traversal
28 * 17-Jul-94 fmu Tries to cope with CDROMs which have an incorrect TOC.
29 * 17-May-94 fmu New option MAYBELOWERCASE (=ML).
30 * 25-Apr-94 fmu The extented attribute record length has to be
31 * considered when reading file sections.
32 * 17-Feb-94 fmu Volume ID must not be longer than 30 characters.
33 * 05-Feb-94 fmu Added support for relocated directories.
34 * 07-Jan-94 fmu Support for drives which don't support the SCSI-2
36 * 01-Jan-94 fmu Added multisession support.
37 * 11-Dec-93 fmu Fixed bug in Iso_Find_Parent().
38 * 02-Dec-93 fmu Bugfix: a logical block of a file extent must not
39 * necessarily start at a logical sector border.
40 * 29-Nov-93 fmu - New function Iso_Block_Size().
41 * - Support for variable logical block sizes.
42 * 15-Nov-93 fmu Uses_High_Sierra_Protocol added.
43 * 13-Nov-93 fmu Bad iso_errno return value in Iso_Open_Obj_In_Directory
45 * 12-Oct-93 fmu Adapted to new VOLUME and CDROM_OBJ structures.
46 * 24-Sep-93 fmu Two further bugs in Seek_Position fixed.
47 * 16-Sep-93 fmu Fixed bug in Seek_Position.
48 * 16-Sep-93 fmu Bugfix: Top level object recognition in CDROM_Info
49 * had to be changed for Rock Ridge disks.
50 * 07-Jul-02 sheutlin various changes when porting to AROS
51 * - global variables are now in a struct Globals *global
54 #include <proto/exec.h>
55 #include <proto/utility.h>
56 #include <exec/types.h>
57 #include <exec/memory.h>
58 #include <utility/date.h>
70 #include "clib_stuff.h"
73 #define FIBF_HIDDEN (1<<7)
76 t_bool
Iso_Is_Top_Level_Object (CDROM_OBJ
*);
78 #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
79 #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
81 int Get_Volume_Name(VOLUME
*p_volume
, char *buf
, int buflen
)
83 char *iso_name
= VOL(p_volume
,pvd
).volume_id
;
85 D(bug("[CDVDFS]\tGet_Volume_Name()\n"));
86 if (p_volume
->protocol
== PRO_JOLIET
)
87 return Get_Joliet_Name(p_volume
->global
, iso_name
, buf
, 32);
89 CopyMem(iso_name
, buf
, 32);
94 int Get_File_Name(VOLUME
*volume
, directory_record
*dir
, char *buf
, int buflen
)
98 D(bug("[CDVDFS]\tGet_File_Name()\n"));
100 switch (volume
->protocol
)
103 len
= Get_Joliet_Name(volume
->global
, dir
->file_id
, buf
, dir
->file_id_length
);
107 len
= Get_RR_File_Name(volume
, dir
, buf
, buflen
);
111 /* Fall through... */
114 len
= dir
->file_id_length
;
115 CopyMem(dir
->file_id
, buf
, len
);
122 /* Check whether the given volume uses the ISO 9660 Protocol.
123 * The protocol is identified by the sequence
124 * 'C' 'D' '0' '0' '1'
125 * in the 2nd..6th byte of sector 16 of a track.
127 * All data tracks on the disk are examined.
129 * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
132 t_bool
Uses_Iso_Protocol(CDROM
*p_cdrom
, t_ulong
*p_offset
)
137 D(bug("[CDVDFS]\tUses_Iso_Protocol()\n"));
140 If Data_Tracks() returns -1, then the drive probably doesn't support
141 the SCSI-2 READ TOC command.
143 if ((len
= Data_Tracks(p_cdrom
, &buf
)) < 0)
146 if (!Read_Chunk(p_cdrom
, 16))
148 return StrNCmp((char *) p_cdrom
->buffer
+ 1, "CD001", 5) == 0;
155 Use a vendor-specific command to find the offset of the last
159 Find_Last_Session(p_cdrom
, p_offset
) &&
160 Read_Chunk(p_cdrom
, 16 + *p_offset
) &&
161 StrNCmp((char *) p_cdrom
->buffer
+ 1, "CD001", 5) == 0
168 /* Search all data tracks for valid primary volume descriptors: */
169 for (i
=len
-1; i
>=0; i
--)
172 if (!Read_Chunk(p_cdrom
, 16 + *p_offset
))
174 if (StrNCmp((char *) p_cdrom
->buffer
+ 1, "CD001", 5) == 0)
184 On some disks, the information in the TOC may not be valid. Therefore
185 also check sector 16:
187 if (!Read_Chunk(p_cdrom
, 16))
189 if (StrNCmp((char *) p_cdrom
->buffer
+ 1, "CD001", 5) == 0)
198 /* Check whether the given volume uses the High Sierra Protocol.
199 * The protocol is identified by the sequence
200 * 'C' 'D' 'R' 'O' 'M'
201 * in the 10th..14th byte of sector 16.
203 * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
206 t_bool
Uses_High_Sierra_Protocol(CDROM
*p_cdrom
)
208 D(bug("[CDVDFS]\tUses_High_Sierra_Protocol()\n"));
209 if (!Read_Chunk(p_cdrom
, 16))
212 return StrNCmp((char *) p_cdrom
->buffer
+ 9, "CDROM", 5) == 0;
215 static t_handler
const g_iso_handler
;
216 t_bool
Iso_Init_Vol_Info(VOLUME
*p_volume
, int p_skip
, t_ulong p_offset
, t_ulong p_svd_offset
)
218 struct CDVDBase
*global
= p_volume
->global
;
219 long loc
= p_svd_offset
+ p_offset
;
221 D(bug("[CDVDFS]\tIso_Init_Vol_Info()\n"));
223 p_volume
->handler
= &g_iso_handler
;
224 p_volume
->vol_info
= AllocMem (sizeof (t_iso_vol_info
), MEMF_PUBLIC
);
225 if (!p_volume
->vol_info
)
227 global
->iso_errno
= ISOERR_NO_MEMORY
;
233 if (!Read_Chunk(p_volume
->cd
, loc
))
235 global
->iso_errno
= ISOERR_SCSI_ERROR
;
236 FreeMem (p_volume
->vol_info
, sizeof (t_iso_vol_info
));
240 if ((p_volume
->cd
->buffer
[0] == 1) || (p_volume
->cd
->buffer
[0] == 2))
244 p_volume
->cd
->buffer
,
246 sizeof (prim_vol_desc
)
251 if (p_volume
->cd
->buffer
[0] == 255 || loc
> 1000)
253 global
->iso_errno
= ISOERR_NO_PVD
;
254 FreeMem (p_volume
->vol_info
, sizeof (t_iso_vol_info
));
261 VOL(p_volume
,skip
) = p_skip
;
263 switch (VOL(p_volume
,pvd
).block_size
)
266 VOL(p_volume
,blockshift
) = 2;
269 VOL(p_volume
,blockshift
) = 1;
273 VOL(p_volume
,blockshift
) = 0;
278 Look at the system ID to find out if the CD is supposed
279 to feature proper file names. These are CDs made for use
280 with the CDTV and the CD³² (both share the "CDTV" system ID)
281 and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
282 created by Mkisofs. If any of these IDs is found the
283 file name to lower case conversion is temporarily
284 disabled if the "ML=MAYBELOWERCASE" option has been selected.
288 p_volume
->protocol
== PRO_ROCK
|| p_volume
->protocol
== PRO_JOLIET
||
289 !StrNCmp(VOL(p_volume
,pvd
).system_id
,"CDTV",4) ||
290 !StrNCmp(VOL(p_volume
,pvd
).system_id
,"AMIGA",5)
292 p_volume
->mixed_char_filenames
= TRUE
;
294 p_volume
->mixed_char_filenames
= FALSE
;
299 void Iso_Close_Vol_Info(VOLUME
*p_volume
)
301 D(bug("[CDVDFS]\tIso_Close_Vol_Info()\n"));
302 FreeMem (p_volume
->vol_info
, sizeof (t_iso_vol_info
));
305 CDROM_OBJ
*Iso_Alloc_Obj(struct CDVDBase
*global
, int p_length_of_dir_record
)
309 D(bug("[CDVDFS]\tIso_Alloc_Obj()\n"));
311 obj
= AllocMem (sizeof (CDROM_OBJ
), MEMF_PUBLIC
| MEMF_CLEAR
);
314 global
->iso_errno
= ISOERR_NO_MEMORY
;
318 obj
->global
= global
;
319 obj
->obj_info
= AllocMem (sizeof (t_iso_obj_info
), MEMF_PUBLIC
);
322 FreeMem (obj
, sizeof (CDROM_OBJ
));
326 OBJ(obj
,dir
) = AllocMem (p_length_of_dir_record
, MEMF_PUBLIC
);
329 global
->iso_errno
= ISOERR_NO_MEMORY
;
330 FreeMem (obj
->obj_info
, sizeof (t_iso_obj_info
));
331 FreeMem (obj
, sizeof (CDROM_OBJ
));
335 D(bug("[CDVDFS]\tIso_Alloc_Obj = %08lx\n", obj
));
340 /* Get the "CDROM object" for the root directory of the volume.
343 CDROM_OBJ
*Iso_Open_Top_Level_Directory(VOLUME
*p_volume
)
347 D(bug("[CDVDFS]\tIso_Open_Top_Level_Directory()\n"));
349 obj
= Iso_Alloc_Obj(p_volume
->global
, VOL(p_volume
,pvd
).root
.length
);
353 obj
->directory_f
= TRUE
;
354 obj
->volume
= p_volume
;
358 &VOL(p_volume
,pvd
).root
,
360 VOL(p_volume
,pvd
).root
.length
366 /* Compare the name of the directory entry dir on the volume volume
367 * with the C string p_name, and return 1 if both strings are equal.
368 * NOTE: dir may contain a file name (with version number) or a directory
369 * name (without version number).
372 int Names_Equal(VOLUME
*volume
, directory_record
*dir
, char *p_name
)
374 struct CDVDBase
*global
= volume
->global
;
378 len
= Get_File_Name(volume
, dir
, buf
, sizeof(buf
));
380 D(bug("[CDVDFS]\tComparing names '%s' <=> '%s'\n", p_name
, buf
));
382 if (Strnicmp(buf
, p_name
, len
) == 0 && p_name
[len
] == 0)
384 D(bug("[CDVDFS]\t-> Equal\n"));
388 if (volume
->protocol
== PRO_ROCK
389 && !(buf
[len
-2] == ';' && buf
[len
-1] == '1'))
391 D(bug("[CDVDFS]\t-> Not Equal\n"));
395 /* compare without version number: */
397 for (pos
=len
-1; pos
>=0; pos
--)
403 D(bug("[CDVDFS]\t-> checking some more\n"));
404 return (Strnicmp(buf
, p_name
, pos
) == 0 && p_name
[pos
] == 0);
408 D(bug("[CDVDFS]\t-> Not Equal\n"));
413 /* Get a record from a directory.
414 * p_location is a LOGICAL BLOCK number.
416 directory_record
*Get_Directory_Record
417 (VOLUME
*p_volume
, uint32_t p_location
, uint32_t p_offset
)
419 struct CDVDBase
*global
= p_volume
->global
;
423 D(bug("[CDVDFS]\tGet_Directory_Record(%lu, %lu): blockshift = %lu\n", p_location
, p_offset
, VOL(p_volume
, blockshift
)));
424 loc
= (p_location
>> VOL(p_volume
,blockshift
)) + (p_offset
>> 11);
425 D(bug("[CDVDFS]\tResult sector = %lu\n", loc
));
427 if (!Read_Chunk(p_volume
->cd
, loc
))
429 D(bug("[CDVDFS]\tRead failed\n"));
430 global
->iso_errno
= ISOERR_SCSI_ERROR
;
434 len
= p_volume
->cd
->buffer
[p_offset
& 2047];
437 CopyMem(p_volume
->cd
->buffer
+ (p_offset
& 2047), p_volume
->buffer
, len
);
440 directory_record
*dr
= (directory_record
*)p_volume
->buffer
;
441 bug("[CDVDFS]\tEntry: >");
442 for (x
=0; x
<dr
->file_id_length
; x
++)
443 bug("%c", dr
->file_id
[x
]);
449 D(bug("[CDVDFS]\t== Last entry ==\n"));
450 p_volume
->buffer
[0] = 0; /* mark as last record */
453 return (directory_record
*)p_volume
->buffer
;
456 /* Create a "CDROM object" for the directory which is located
457 * at sector p_location.
460 CDROM_OBJ
*Iso_Create_Directory_Obj(VOLUME
*p_volume
, uint32_t p_location
)
462 struct CDVDBase
*global
= p_volume
->global
;
463 directory_record
*dir
;
469 D(bug("[CDVDFS]\tIso_Create_Directory_Obj(%ld)\n", p_location
));
471 if (p_location
== VOL(p_volume
,pvd
).root
.extent_loc
)
472 return Iso_Open_Top_Level_Directory(p_volume
);
474 dir
= Get_Directory_Record(p_volume
, p_location
, 0);
477 D(bug("[CDVDFS]\tNo directory record for '.'\n"));
481 dir
= Get_Directory_Record(p_volume
, p_location
, dir
->length
);
484 D(bug("[CDVDFS]\tNo directory record for '..'\n"));
488 loc
= dir
->extent_loc
;
489 len
= dir
->data_length
;
494 D(bug("[CDVDFS]\tNo more elements.\n"));
498 dir
= Get_Directory_Record(p_volume
, loc
, offset
);
501 D(bug("[CDVDFS]\tFailed to read next entry\n"));
507 D(bug("[CDVDFS]\tAdvancing to next sector\n"));
508 /* go to next logical sector: */
509 offset
= (offset
& 0xfffff800) + 2048;
512 if (dir
->extent_loc
== p_location
)
514 offset
+= dir
->length
;
517 obj
= Iso_Alloc_Obj(global
, dir
->length
);
520 D(bug("[CDVDFS]\tFailed to allocate object\n"));
524 obj
->directory_f
= TRUE
;
525 obj
->volume
= p_volume
;
527 CopyMem(dir
, OBJ(obj
,dir
), dir
->length
);
528 D(bug("[CDVDFS]\tObject %08lx allocated and initialized\n", obj
));
534 /* Open the object with name p_name in the directory p_dir.
535 * p_name must not contain '/' or ':' characters.
538 CDROM_OBJ
*Iso_Open_Obj_In_Directory(CDROM_OBJ
*p_dir
, char *p_name
)
540 struct CDVDBase
*global
= p_dir
->global
;
541 uint32_t loc
= OBJ(p_dir
,dir
)->extent_loc
+ OBJ(p_dir
,dir
)->ext_attr_length
;
542 uint32_t len
= OBJ(p_dir
,dir
)->data_length
;
543 directory_record
*dir
;
548 /* skip first two entries: */
550 D(bug("[CDVDFS]\tIso_Open_Obj_In_Directory(%s)\n", p_name
));
551 dir
= Get_Directory_Record(p_dir
->volume
, loc
, 0);
554 D(bug("[CDVDFS]\tNo directory record for '.'\n"));
558 offset
= dir
->length
;
559 dir
= Get_Directory_Record(p_dir
->volume
, loc
, offset
);
562 D(bug("[CDVDFS]\tNo directory record for '..'\n"));
566 offset
+= dir
->length
;
571 D(bug("[CDVDFS]\tNo more directory records\n"));
572 global
->iso_errno
= ISOERR_NOT_FOUND
;
576 dir
= Get_Directory_Record(p_dir
->volume
, loc
, offset
);
579 D(bug("[CDVDFS]\tFailed to read directory records\n"));
585 /* go to next logical sector: */
586 D(bug("[CDVDFS]\tRead dir advancing to next sector\n"));
587 offset
= (offset
& 0xfffff800) + 2048;
591 /* We skip files that are marked as associated */
592 if (((dir
->flags
& FILE_FLAG_ASSOCIATED
) == 0) &&
593 Names_Equal(p_dir
->volume
, dir
, p_name
))
596 D(bug("[CDVDFS]\tRead dir advancing to next record\n"));
597 offset
+= dir
->length
;
600 if (p_dir
->volume
->protocol
== PRO_ROCK
&& (cl
= RR_Child_Link(p_dir
->volume
, dir
)) >= 0)
602 return Iso_Create_Directory_Obj(p_dir
->volume
, cl
);
605 obj
= Iso_Alloc_Obj(global
, dir
->length
);
608 D(bug("[CDVDFS]\tFailed to create object\n"));
612 obj
->directory_f
= (dir
->flags
& FILE_FLAG_DIRECTORY
);
613 obj
->protection
= (dir
->flags
& FILE_FLAG_HIDDEN
) ? FIBF_HIDDEN
: 0;
614 if (p_dir
->volume
->protocol
== PRO_ROCK
&& Is_A_Symbolic_Link(p_dir
->volume
, dir
, &obj
->protection
))
617 obj
->directory_f
= 0;
619 CopyMem(dir
, OBJ(obj
,dir
), dir
->length
);
620 obj
->volume
= p_dir
->volume
;
622 if (!obj
->directory_f
)
623 OBJ(obj
,parent_loc
) = loc
;
625 D(bug("[CDVDFS]\tObject %08lx created and initialized\n", obj
));
630 /* Close a "CDROM object" and deallocate all associated resources.
633 void Iso_Close_Obj(CDROM_OBJ
*p_object
)
635 D(bug("[CDVDFS]\tIso_Close_Obj(%08lx)\n", p_object
));
636 FreeMem (OBJ(p_object
,dir
), OBJ(p_object
,dir
)->length
);
637 FreeMem (p_object
->obj_info
, sizeof (t_iso_obj_info
));
638 FreeMem (p_object
, sizeof (CDROM_OBJ
));
639 D(bug("[CDVDFS]\tObject disposed\n"));
642 /* Read bytes from a file.
645 int Iso_Read_From_File(CDROM_OBJ
*p_file
, char *p_buffer
, int p_buffer_length
)
647 struct CDVDBase
*global
= p_file
->global
;
649 int remain_block
, remain_file
, remain
;
651 VOLUME
*vol
= p_file
->volume
;
660 D(bug("[CDVDFS]\tIso_Read_From_File()\n"));
662 if (p_file
->pos
== OBJ(p_file
,dir
)->data_length
)
664 /* at end of file: */
668 blockshift
= VOL(vol
,blockshift
);
669 /* 'firstblock' is the first logical block of the file section: */
671 OBJ(p_file
,dir
)->extent_loc
+ OBJ(p_file
,dir
)->ext_attr_length
;
673 'offset' is the offset of the first logical block of the file
674 extent from the first logical (2048-byte-)sector.
677 offset
= ((firstblock
& ((1<<blockshift
)-1))<< (11-blockshift
));
681 'ext_loc' is the first logical sector of the file extent.
682 'loc' is the first logical sector to be read.
684 ext_loc
= firstblock
>> blockshift
;
685 loc
= ext_loc
+ ((p_file
->pos
+ offset
) >> 11);
686 todo
= p_buffer_length
;
688 offset
+= p_file
->pos
;
689 offset
&= 2047; // this is the offset in first block;
692 * how much data available in next read chunk?
694 remain_block
= (SCSI_BUFSIZE
<< 4) - ((loc
<< 11) & ((SCSI_BUFSIZE
<< 4) - 1)) - offset
;
698 D(bug("[CDVDFS]\tRead: BPos: %6ld; FPos: %6ld; Ofst: %6ld; Blck: %6ld;\n", buf_pos
, p_file
->pos
, offset
, loc
));
700 if (!Read_Chunk(cd
, loc
))
702 global
->iso_errno
= ISOERR_SCSI_ERROR
;
707 * how much data left in a file?
709 remain_file
= OBJ(p_file
,dir
)->data_length
- p_file
->pos
;
712 * how much data remain in file vs chunk?
714 remain
= (remain_block
< remain_file
) ? remain_block
: remain_file
;
717 * and how much user wants to read?
719 len
= (todo
< remain
) ? todo
: remain
;
721 D(bug("[CDVDFS]\tRead: Chnk: %6ld; File: %6ld; Todo: %6ld; Read: %6ld;\n", remain_block
, remain_file
, todo
, len
));
725 CopyMem ((APTR
) (cd
->buffer
+ offset
), (APTR
) (p_buffer
+ buf_pos
), len
);
728 * update positions, offsets, todo
735 * if read it all - end
737 if (p_file
->pos
>= OBJ(p_file
,dir
)->data_length
)
740 remain_block
= (SCSI_BUFSIZE
<< 4);
743 loc
= (loc
+ 16) &~ 15;
749 t_ulong
Extract_Date(struct CDVDBase
*global
, directory_record
*p_dir_record
)
751 struct ClockData ClockData
;
753 D(bug("[CDVDFS]\tIso_Extract_Date\n"));
754 ClockData
.sec
= p_dir_record
->second
;
755 ClockData
.min
= p_dir_record
->minute
;
756 ClockData
.hour
= p_dir_record
->hour
;
757 ClockData
.mday
= p_dir_record
->day
;
758 ClockData
.wday
= 0; /* is ignored by CheckDate() and Date2Amiga() */
759 ClockData
.month
= p_dir_record
->month
;
760 ClockData
.year
= p_dir_record
->year
+ 1900;
762 if (CheckDate (&ClockData
))
763 return Date2Amiga (&ClockData
);
768 /* Return information on a "CDROM object."
771 int Iso_CDROM_Info(CDROM_OBJ
*p_obj
, CDROM_INFO
*p_info
)
775 D(bug("[CDVDFS]\tIso_CDROM_Info\n"));
777 if (Iso_Is_Top_Level_Object (p_obj
))
779 p_info
->name_length
= 1;
780 p_info
->name
[0] = ':';
781 p_info
->directory_f
= TRUE
;
782 p_info
->file_length
= 0;
783 p_info
->date
= Volume_Creation_Date(p_obj
->volume
);
784 p_info
->protection
= 0;
785 p_info
->comment_length
= 0;
789 directory_record
*rec
= OBJ(p_obj
, dir
);
791 p_info
->name_length
= Get_File_Name(p_obj
->volume
, rec
, p_info
->name
, sizeof(p_info
->name
));
792 p_info
->directory_f
= p_obj
->directory_f
;
793 p_info
->symlink_f
= p_obj
->symlink_f
;
794 p_info
->file_length
= OBJ(p_obj
,dir
)->data_length
;
795 p_info
->date
= Extract_Date(p_obj
->global
, OBJ(p_obj
,dir
));
796 p_info
->protection
= p_obj
->protection
;
798 if (p_obj
->volume
->protocol
== PRO_ROCK
&&
799 (len
= Get_RR_File_Comment(p_obj
->volume
, rec
, &p_info
->protection
, p_info
->comment
, sizeof(p_info
->comment
))) > 0)
800 p_info
->comment_length
= len
;
802 p_info
->comment_length
= 0;
808 /* Browse all entries in a directory.
812 (CDROM_OBJ
*p_dir
, CDROM_INFO
*p_info
, uint32_t *p_offset
)
814 struct CDVDBase
*global
= p_dir
->global
;
816 directory_record
*rec
;
819 D(bug("[CDVDFS]\tIso_Examine_Next()\n"));
821 if (!p_dir
->directory_f
|| p_dir
->symlink_f
)
823 global
->iso_errno
= ISOERR_BAD_ARGUMENTS
;
829 /* skip first two directory entries: */
831 rec
= Get_Directory_Record
834 OBJ(p_dir
,dir
)->extent_loc
+ OBJ(p_dir
,dir
)->ext_attr_length
,
840 offset
= rec
->length
;
842 rec
= Get_Directory_Record
845 OBJ(p_dir
,dir
)->extent_loc
+ OBJ(p_dir
,dir
)->ext_attr_length
,
851 *p_offset
= offset
+ rec
->length
;
857 if (OBJ(p_dir
,dir
)->data_length
<= *p_offset
)
860 rec
= Get_Directory_Record
863 OBJ(p_dir
,dir
)->extent_loc
+ OBJ(p_dir
,dir
)->ext_attr_length
,
869 if (rec
->length
== 0)
871 /* go to next logical sector: */
872 *p_offset
= (*p_offset
& 0xfffff800) + 2048;
878 *p_offset
+= rec
->length
;
879 } while (rec
->flags
& FILE_FLAG_ASSOCIATED
);
881 p_info
->name_length
= Get_File_Name(p_dir
->volume
, rec
, p_info
->name
, sizeof(p_info
->name
));
883 p_info
->protection
= (rec
->flags
& FILE_FLAG_HIDDEN
) ? FIBF_HIDDEN
: 0;
885 if (p_dir
->volume
->protocol
== PRO_ROCK
&& Is_A_Symbolic_Link(p_dir
->volume
, rec
, &p_info
->protection
))
887 p_info
->symlink_f
= 1;
888 p_info
->directory_f
= 0;
890 else if (p_dir
->volume
->protocol
== PRO_ROCK
&& Has_System_Use_Field(p_dir
->volume
, rec
, "CL"))
892 p_info
->symlink_f
= 0;
893 p_info
->directory_f
= 1;
897 p_info
->symlink_f
= 0;
898 p_info
->directory_f
= rec
->flags
& FILE_FLAG_DIRECTORY
;
901 p_info
->file_length
= rec
->data_length
;
902 p_info
->date
= Extract_Date(global
, rec
);
904 if (p_dir
->volume
->protocol
== PRO_ROCK
&&
905 (len
= Get_RR_File_Comment(p_dir
->volume
, rec
, &p_info
->protection
, p_info
->comment
, sizeof(p_info
->name
))) > 0)
906 p_info
->comment_length
= len
;
908 p_info
->comment_length
= 0;
910 p_info
->suppl_info
= rec
;
915 /* Clone a "CDROM object info."
918 void *Iso_Clone_Obj_Info(void *p_info
)
920 t_iso_obj_info
*info
= (t_iso_obj_info
*) p_info
;
923 D(bug("[CDVDFS]\tIso_Clone_Obj_Info\n"));
925 new = AllocMem (sizeof (t_iso_obj_info
), MEMF_PUBLIC
);
929 CopyMem(info
, new, sizeof (t_iso_obj_info
));
931 new->dir
= AllocMem (info
->dir
->length
, MEMF_PUBLIC
);
934 FreeMem (new, sizeof (t_iso_obj_info
));
937 CopyMem(info
->dir
, new->dir
, info
->dir
->length
);
942 /* Find parent directory.
945 CDROM_OBJ
*Iso_Find_Parent(CDROM_OBJ
*p_object
)
947 directory_record
*dir
;
951 D(bug("[CDVDFS]\tIso_Find_Parent(%08lx)\n", p_object
));
953 if (p_object
->directory_f
)
955 OBJ(p_object
,dir
)->extent_loc
+ OBJ(p_object
,dir
)->ext_attr_length
;
957 dir_loc
= OBJ(p_object
,parent_loc
);
959 dir
= Get_Directory_Record(p_object
->volume
, dir_loc
, 0);
963 if (p_object
->directory_f
)
965 dir
= Get_Directory_Record(p_object
->volume
, dir_loc
, dir
->length
);
969 p_object
->volume
->protocol
== PRO_ROCK
&&
970 (pl
= RR_Parent_Link(p_object
->volume
, dir
)) >= 0
972 return Iso_Create_Directory_Obj(p_object
->volume
, pl
);
975 return Iso_Create_Directory_Obj(p_object
->volume
, dir
->extent_loc
);
978 /* Test if p_object is the root directory.
981 t_bool
Iso_Is_Top_Level_Object (CDROM_OBJ
*p_object
)
983 return p_object
->directory_f
&&
984 OBJ(p_object
,dir
)->extent_loc
==
985 VOL(p_object
->volume
,pvd
).root
.extent_loc
;
988 /* Test if two objects are equal.
991 t_bool
Iso_Same_Objects (CDROM_OBJ
*p_obj1
, CDROM_OBJ
*p_obj2
)
993 return (OBJ(p_obj1
,dir
)->extent_loc
==
994 OBJ(p_obj2
,dir
)->extent_loc
);
998 * Convert p_num digits into an integer value:
1001 int Digs_To_Int (char *p_digits
, int p_num
)
1006 for (i
=0; i
<p_num
; i
++)
1007 result
= result
* 10 + p_digits
[i
] - '0';
1013 * Return volume creation date as number of seconds since 1-Jan-1978:
1016 t_ulong
Iso_Creation_Date(VOLUME
*p_volume
)
1018 struct CDVDBase
*global
= p_volume
->global
;
1019 struct ClockData ClockData
;
1020 char *dt
= VOL(p_volume
,pvd
).vol_creation
;
1022 D(bug("[CDVDFS]\tIso_Creation_Date\n"));
1024 ClockData
.sec
= Digs_To_Int (dt
+12, 2);
1025 ClockData
.min
= Digs_To_Int (dt
+10, 2);
1026 ClockData
.hour
= Digs_To_Int (dt
+8, 2);
1027 ClockData
.mday
= Digs_To_Int (dt
+6, 2);
1028 ClockData
.wday
= 0; /* is ignored by CheckDate() and Date2Amiga() */
1029 ClockData
.month
= Digs_To_Int (dt
+4, 2);
1030 ClockData
.year
= Digs_To_Int (dt
, 4);
1032 if (CheckDate (&ClockData
))
1033 return Date2Amiga (&ClockData
);
1038 t_ulong
Iso_Volume_Size (VOLUME
*p_volume
)
1040 return VOL(p_volume
,pvd
).space_size
;
1043 t_ulong
Iso_Block_Size (VOLUME
*p_volume
)
1045 return VOL(p_volume
,pvd
).block_size
;
1048 void Iso_Volume_ID(VOLUME
*p_volume
, char *p_buffer
, int p_buf_length
)
1054 D(bug("[CDVDFS]\tIso_Volume_ID\n"));
1056 iso_len
= Get_Volume_Name(p_volume
, buf
, sizeof(buf
));
1057 for (; iso_len
; iso_len
--)
1059 if (buf
[iso_len
-1] != ' ')
1062 len
= (iso_len
> p_buf_length
-1) ? p_buf_length
-1 : iso_len
;
1064 CopyMem(buf
, p_buffer
, len
);
1068 t_ulong
Iso_Location (CDROM_OBJ
*p_object
)
1070 return OBJ(p_object
,dir
)->extent_loc
;
1073 t_ulong
Iso_File_Length (CDROM_OBJ
*p_obj
)
1075 return OBJ(p_obj
,dir
)->data_length
;
1078 static t_handler
const g_iso_handler
=
1081 Iso_Open_Top_Level_Directory
,
1082 Iso_Open_Obj_In_Directory
,
1089 Iso_Is_Top_Level_Object
,