revert between 56095 -> 55830 in arch
[AROS.git] / rom / filesys / CDVDFS / src / iso9660.c
blobe05f600ae31e09276195ab1e15f95cec06ed11cc
1 /* iso9660.c:
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.
8 * All rights reserved.
9 * This software may be freely distributed and redistributed for
10 * non-commercial purposes, provided this notice is included.
11 * ----------------------------------------------------------------------
12 * History:
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
27 * of the TOC.
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
35 * READ TOC command.
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
44 * corrected.
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>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <ctype.h>
63 #include "debug.h"
64 #include "cdrom.h"
65 #include "iso9660.h"
66 #include "joliet.h"
67 #include "rock.h"
68 #include "globals.h"
70 #include "clib_stuff.h"
72 #ifndef FIBF_HIDDEN
73 #define FIBF_HIDDEN (1<<7)
74 #endif
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);
88 else {
89 CopyMem(iso_name, buf, 32);
90 return 32;
94 int Get_File_Name(VOLUME *volume, directory_record *dir, char *buf, int buflen)
96 int len;
98 D(bug("[CDVDFS]\tGet_File_Name()\n"));
100 switch (volume->protocol)
102 case PRO_JOLIET:
103 len = Get_Joliet_Name(volume->global, dir->file_id, buf, dir->file_id_length);
104 break;
106 case PRO_ROCK:
107 len = Get_RR_File_Name(volume, dir, buf, buflen);
108 if (len > 0)
109 break;
111 /* Fall through... */
113 default:
114 len = dir->file_id_length;
115 CopyMem(dir->file_id, buf, len);
116 break;
118 buf[len] = 0;
119 return 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)
134 int i, len;
135 t_ulong *buf;
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)
145 *p_offset = 0;
146 if (!Read_Chunk(p_cdrom, 16))
147 return FALSE;
148 return StrNCmp((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
151 if (len == 0)
152 return FALSE;
155 Use a vendor-specific command to find the offset of the last
156 session:
158 if (
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
164 FreeVec (buf);
165 return TRUE;
168 /* Search all data tracks for valid primary volume descriptors: */
169 for (i=len-1; i>=0; i--)
171 *p_offset = buf[i];
172 if (!Read_Chunk(p_cdrom, 16 + *p_offset))
173 continue;
174 if (StrNCmp((char *) p_cdrom->buffer + 1, "CD001", 5) == 0)
176 FreeVec (buf);
177 return TRUE;
181 FreeVec (buf);
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))
188 return FALSE;
189 if (StrNCmp((char *) p_cdrom->buffer + 1, "CD001", 5) == 0)
191 *p_offset = 0;
192 return TRUE;
195 return FALSE;
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))
210 return FALSE;
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;
228 return FALSE;
231 for (;;)
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));
237 return FALSE;
240 if ((p_volume->cd->buffer[0] == 1) || (p_volume->cd->buffer[0] == 2))
242 CopyMem
244 p_volume->cd->buffer,
245 &VOL(p_volume,pvd),
246 sizeof (prim_vol_desc)
248 break;
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));
255 return FALSE;
258 loc++;
261 VOL(p_volume,skip) = p_skip;
263 switch (VOL(p_volume,pvd).block_size)
265 case 512:
266 VOL(p_volume,blockshift) = 2;
267 break;
268 case 1024:
269 VOL(p_volume,blockshift) = 1;
270 break;
271 case 2048:
272 default:
273 VOL(p_volume,blockshift) = 0;
274 break;
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.
287 if (
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;
293 else
294 p_volume->mixed_char_filenames = FALSE;
296 return TRUE;
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)
307 CDROM_OBJ *obj;
309 D(bug("[CDVDFS]\tIso_Alloc_Obj()\n"));
311 obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
312 if (!obj)
314 global->iso_errno = ISOERR_NO_MEMORY;
315 return NULL;
318 obj->global = global;
319 obj->obj_info = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
320 if (!obj->obj_info)
322 FreeMem (obj, sizeof (CDROM_OBJ));
323 return NULL;
326 OBJ(obj,dir) = AllocMem (p_length_of_dir_record, MEMF_PUBLIC);
327 if (!OBJ(obj,dir))
329 global->iso_errno = ISOERR_NO_MEMORY;
330 FreeMem (obj->obj_info, sizeof (t_iso_obj_info));
331 FreeMem (obj, sizeof (CDROM_OBJ));
332 return NULL;
335 D(bug("[CDVDFS]\tIso_Alloc_Obj = %08lx\n", obj));
337 return obj;
340 /* Get the "CDROM object" for the root directory of the volume.
343 CDROM_OBJ *Iso_Open_Top_Level_Directory(VOLUME *p_volume)
345 CDROM_OBJ *obj;
347 D(bug("[CDVDFS]\tIso_Open_Top_Level_Directory()\n"));
349 obj = Iso_Alloc_Obj(p_volume->global, VOL(p_volume,pvd).root.length);
350 if (!obj)
351 return NULL;
353 obj->directory_f = TRUE;
354 obj->volume = p_volume;
355 obj->pos = 0;
356 CopyMem
358 &VOL(p_volume,pvd).root,
359 OBJ(obj,dir),
360 VOL(p_volume,pvd).root.length
363 return obj;
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;
375 int pos, len;
376 char buf[256];
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"));
385 return TRUE;
388 if (volume->protocol == PRO_ROCK
389 && !(buf[len-2] == ';' && buf[len-1] == '1'))
391 D(bug("[CDVDFS]\t-> Not Equal\n"));
392 return FALSE;
395 /* compare without version number: */
397 for (pos=len-1; pos>=0; pos--)
398 if (buf[pos] == ';')
399 break;
401 if (pos>=0)
403 D(bug("[CDVDFS]\t-> checking some more\n"));
404 return (Strnicmp(buf, p_name, pos) == 0 && p_name[pos] == 0);
406 else
408 D(bug("[CDVDFS]\t-> Not Equal\n"));
409 return FALSE;
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;
420 int len;
421 int loc;
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;
431 return NULL;
434 len = p_volume->cd->buffer[p_offset & 2047];
435 if (len)
437 CopyMem(p_volume->cd->buffer + (p_offset & 2047), p_volume->buffer, len);
439 int x;
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]);
444 bug("<\n");
447 else
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;
464 uint32_t loc;
465 int offset = 0;
466 CDROM_OBJ *obj;
467 uint32_t len;
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);
475 if (!dir)
477 D(bug("[CDVDFS]\tNo directory record for '.'\n"));
478 return NULL;
481 dir = Get_Directory_Record(p_volume, p_location, dir->length);
482 if (!dir)
484 D(bug("[CDVDFS]\tNo directory record for '..'\n"));
485 return NULL;
488 loc = dir->extent_loc;
489 len = dir->data_length;
490 for (;;)
492 if (offset >= len)
494 D(bug("[CDVDFS]\tNo more elements.\n"));
495 return NULL;
498 dir = Get_Directory_Record(p_volume, loc, offset);
499 if (!dir)
501 D(bug("[CDVDFS]\tFailed to read next entry\n"));
502 return NULL;
505 if (!dir->length)
507 D(bug("[CDVDFS]\tAdvancing to next sector\n"));
508 /* go to next logical sector: */
509 offset = (offset & 0xfffff800) + 2048;
510 continue;
512 if (dir->extent_loc == p_location)
513 break;
514 offset += dir->length;
517 obj = Iso_Alloc_Obj(global, dir->length);
518 if (!obj)
520 D(bug("[CDVDFS]\tFailed to allocate object\n"));
521 return NULL;
524 obj->directory_f = TRUE;
525 obj->volume = p_volume;
526 obj->pos = 0;
527 CopyMem(dir, OBJ(obj,dir), dir->length);
528 D(bug("[CDVDFS]\tObject %08lx allocated and initialized\n", obj));
530 return 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;
544 int offset;
545 CDROM_OBJ *obj;
546 long cl;
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);
552 if (!dir)
554 D(bug("[CDVDFS]\tNo directory record for '.'\n"));
555 return NULL;
558 offset = dir->length;
559 dir = Get_Directory_Record(p_dir->volume, loc, offset);
560 if (!dir)
562 D(bug("[CDVDFS]\tNo directory record for '..'\n"));
563 return NULL;
566 offset += dir->length;
567 for (;;)
569 if (offset >= len)
571 D(bug("[CDVDFS]\tNo more directory records\n"));
572 global->iso_errno = ISOERR_NOT_FOUND;
573 return NULL;
576 dir = Get_Directory_Record(p_dir->volume, loc, offset);
577 if (!dir)
579 D(bug("[CDVDFS]\tFailed to read directory records\n"));
580 return NULL;
583 if (!dir->length)
585 /* go to next logical sector: */
586 D(bug("[CDVDFS]\tRead dir advancing to next sector\n"));
587 offset = (offset & 0xfffff800) + 2048;
588 continue;
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))
594 break;
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);
606 if (!obj)
608 D(bug("[CDVDFS]\tFailed to create object\n"));
609 return NULL;
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))
616 obj->symlink_f = 1;
617 obj->directory_f = 0;
619 CopyMem(dir, OBJ(obj,dir), dir->length);
620 obj->volume = p_dir->volume;
621 obj->pos = 0;
622 if (!obj->directory_f)
623 OBJ(obj,parent_loc) = loc;
625 D(bug("[CDVDFS]\tObject %08lx created and initialized\n", obj));
627 return 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;
648 uint32_t loc;
649 int remain_block, remain_file, remain;
650 int len;
651 VOLUME *vol = p_file->volume;
652 CDROM *cd = vol->cd;
653 int buf_pos = 0;
654 int todo;
655 uint32_t ext_loc;
656 short blockshift;
657 int offset;
658 uint32_t firstblock;
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: */
665 return 0;
668 blockshift = VOL(vol,blockshift);
669 /* 'firstblock' is the first logical block of the file section: */
670 firstblock =
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.
676 if (blockshift)
677 offset = ((firstblock & ((1<<blockshift)-1))<< (11-blockshift));
678 else
679 offset = 0;
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;
696 while (todo)
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;
703 return -1;
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));
723 * copy read data
725 CopyMem ((APTR) (cd->buffer + offset), (APTR) (p_buffer + buf_pos), len);
728 * update positions, offsets, todo
730 buf_pos += len;
731 p_file->pos += len;
732 todo -= len;
735 * if read it all - end
737 if (p_file->pos >= OBJ(p_file,dir)->data_length)
738 break;
740 remain_block = (SCSI_BUFSIZE << 4);
741 offset = 0;
743 loc = (loc + 16) &~ 15;
746 return buf_pos;
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);
764 else
765 return 0;
768 /* Return information on a "CDROM object."
771 int Iso_CDROM_Info(CDROM_OBJ *p_obj, CDROM_INFO *p_info)
773 int len;
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;
787 else
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;
801 else
802 p_info->comment_length = 0;
805 return 1;
808 /* Browse all entries in a directory.
811 int Iso_Examine_Next
812 (CDROM_OBJ *p_dir, CDROM_INFO *p_info, uint32_t *p_offset)
814 struct CDVDBase *global = p_dir->global;
815 uint32_t offset;
816 directory_record *rec;
817 int len;
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;
824 return 0;
827 if (*p_offset == 0)
829 /* skip first two directory entries: */
831 rec = Get_Directory_Record
833 p_dir->volume,
834 OBJ(p_dir,dir)->extent_loc + OBJ(p_dir,dir)->ext_attr_length,
837 if (!rec)
838 return 0;
840 offset = rec->length;
842 rec = Get_Directory_Record
844 p_dir->volume,
845 OBJ(p_dir,dir)->extent_loc + OBJ(p_dir,dir)->ext_attr_length,
846 offset
848 if (!rec)
849 return 0;
851 *p_offset = offset + rec->length;
854 do {
855 for (;;)
857 if (OBJ(p_dir,dir)->data_length <= *p_offset)
858 return 0;
860 rec = Get_Directory_Record
862 p_dir->volume,
863 OBJ(p_dir,dir)->extent_loc + OBJ(p_dir,dir)->ext_attr_length,
864 *p_offset
866 if (!rec)
867 return 0;
869 if (rec->length == 0)
871 /* go to next logical sector: */
872 *p_offset = (*p_offset & 0xfffff800) + 2048;
874 else
875 break;
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;
895 else
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;
907 else
908 p_info->comment_length = 0;
910 p_info->suppl_info = rec;
912 return 1;
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;
921 t_iso_obj_info *new;
923 D(bug("[CDVDFS]\tIso_Clone_Obj_Info\n"));
925 new = AllocMem (sizeof (t_iso_obj_info), MEMF_PUBLIC);
926 if (!new)
927 return NULL;
929 CopyMem(info, new, sizeof (t_iso_obj_info));
931 new->dir = AllocMem (info->dir->length, MEMF_PUBLIC);
932 if (!new->dir)
934 FreeMem (new, sizeof (t_iso_obj_info));
935 return NULL;
937 CopyMem(info->dir, new->dir, info->dir->length);
939 return new;
942 /* Find parent directory.
945 CDROM_OBJ *Iso_Find_Parent(CDROM_OBJ *p_object)
947 directory_record *dir;
948 uint32_t dir_loc;
949 long pl;
951 D(bug("[CDVDFS]\tIso_Find_Parent(%08lx)\n", p_object));
953 if (p_object->directory_f)
954 dir_loc =
955 OBJ(p_object,dir)->extent_loc + OBJ(p_object,dir)->ext_attr_length;
956 else
957 dir_loc = OBJ(p_object,parent_loc);
959 dir = Get_Directory_Record(p_object->volume, dir_loc, 0);
960 if (!dir)
961 return NULL;
963 if (p_object->directory_f)
965 dir = Get_Directory_Record(p_object->volume, dir_loc, dir->length);
966 if (!dir)
967 return NULL;
968 if (
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)
1003 int result = 0;
1004 int i;
1006 for (i=0; i<p_num; i++)
1007 result = result * 10 + p_digits[i] - '0';
1009 return result;
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);
1034 else
1035 return 0;
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)
1050 int iso_len;
1051 int len;
1052 char buf[32];
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] != ' ')
1060 break;
1062 len = (iso_len > p_buf_length-1) ? p_buf_length-1 : iso_len;
1063 if (len > 0)
1064 CopyMem(buf, p_buffer, len);
1065 p_buffer[len] = 0;
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 =
1080 Iso_Close_Vol_Info,
1081 Iso_Open_Top_Level_Directory,
1082 Iso_Open_Obj_In_Directory,
1083 Iso_Find_Parent,
1084 Iso_Close_Obj,
1085 Iso_Read_From_File,
1086 Iso_CDROM_Info,
1087 Iso_Examine_Next,
1088 Iso_Clone_Obj_Info,
1089 Iso_Is_Top_Level_Object,
1090 Iso_Same_Objects,
1091 Iso_Creation_Date,
1092 Iso_Volume_Size,
1093 Iso_Volume_ID,
1094 Iso_Location,
1095 Iso_File_Length,
1096 Iso_Block_Size