2 * Copyright (C) 2013, The AROS Development Team
4 * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
6 * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
12 #include <aros/debug.h>
14 #include <proto/exec.h>
15 #include <proto/dos.h>
16 #include <proto/utility.h>
23 struct CDFSLock il_Public
;
25 UQUAD il_Offset
; /* For read/write offset */
26 ULONG il_ParentExtent
; /* Extent of the parent directory */
27 struct isoPathTable
*il_PathTable
;
31 struct isoVolume iv_Volume
;
32 struct ISOLock iv_RootLock
;
33 TEXT iv_Name
[1 + 32 + 1];
35 ULONG Size
; /* In bytes */
38 struct isoPathTable
**Entry
;
43 static ULONG
ascdec(STRPTR val
, int len
)
47 while ((*val
>= '0' && *val
<= '9') && len
> 0) {
57 #define AMIGA_EPOC 722484 /* Day number of Amiga Epoc, using Zeller */
59 static void ascdate2stamp(ascDate
*asc
, struct DateStamp
*date
)
61 ULONG year
= ascdec(asc
->Year
, 4);
62 ULONG month
= ascdec(asc
->Month
, 2);
63 ULONG day
= ascdec(asc
->Day
, 2);
69 date
->ds_Days
= (365*year
+ year
/4 - year
/100 + year
/400 + day
+ (153*month
+8)/5) - AMIGA_EPOC
;
70 date
->ds_Minute
= ascdec(asc
->Hour
, 2) * 60 +
71 ascdec(asc
->Minute
, 2);
72 date
->ds_Tick
= ascdec(asc
->Second
, 2) * 50 + ascdec(asc
->Hundredth
, 2) / 2;
74 /* FIXME: Adjust for timezone */
77 static void bindate2stamp(binDate
*bin
, struct DateStamp
*date
)
79 ULONG year
= bin
->Years
+ 1900;
80 ULONG month
= bin
->Month
;
87 date
->ds_Days
= (365*year
+ year
/4 - year
/100 + year
/400 + day
+ (153*month
+8)/5) - AMIGA_EPOC
;
88 date
->ds_Minute
= bin
->Hour
* 60 +
90 date
->ds_Tick
= bin
->Second
* 50;
92 /* FIXME: Adjust for timezone */
95 static inline ULONG
isoRead32LM(int32LM
*lm
)
97 #if _BYTE_ORDER == _BIG_ENDIAN
98 return lm
->MSB
? lm
->MSB
: (ULONG
)AROS_LE2LONG(lm
->LSB
);
99 #elif _BYTE_ORDER == _LITTLE_ENDIAN
100 return lm
->LSB
? lm
->LSB
: (ULONG
)AROS_BE2LONG(lm
->MSB
);
101 #else /* Wacky byte order? Impossible in this day and age. */
102 #error PDP11s are no longer supported.
106 static BOOL
isoParseDir(struct CDFSVolume
*vol
, struct ISOLock
*il
, struct isoDirectory
*dir
, ULONG iparent
)
108 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
109 struct FileInfoBlock
*fib
= &il
->il_Public
.cl_FileInfoBlock
;
110 struct FileLock
*fl
= &il
->il_Public
.cl_FileLock
;
111 struct ISOVolume
*iv
= vol
->cv_Private
;
114 BOOL has_Amiga_Protections
= FALSE
;
115 BOOL has_RockRidge
= FALSE
;
118 il
->il_Extent
= isoRead32LM(&dir
->ExtentLocation
);
119 il
->il_PathTable
= NULL
;
121 il
->il_Extent
= il
->il_PathTable
->ExtentLocation
;
122 iparent
= iv
->iv_PathTable
.Entry
[il
->il_PathTable
->ParentDirectory
-1]->ExtentLocation
;
125 D(bug("%s: \"%s\" Extent @0x%08x, Parent 0x%08x, Flags 0x%02x\n", __func__
,
126 dir
? dir
->FileIdentifier
: il
->il_PathTable
->DirectoryIdentifier
,
127 il
->il_Extent
, iparent
, dir
? dir
->Flags
: 0));
129 if (dir
&& dir
->Flags
& (ISO_Directory_ASSOC
| ISO_Directory_HIDDEN
))
132 /* No need to re-parse the root lock */
133 if (iv
&& il
->il_Extent
== iv
->iv_RootLock
.il_Extent
) {
134 CopyMem(&iv
->iv_RootLock
, il
, sizeof(*il
));
138 /* The starting location of the file is its unique 'key' */
139 fl
->fl_Key
= il
->il_Extent
;
142 fib
->fib_Size
= isoRead32LM(&dir
->DataLength
);
143 bindate2stamp(&dir
->RecordingDate
, &fib
->fib_Date
);
144 fib
->fib_DirEntryType
= (dir
->Flags
& ISO_Directory_ISDIR
) ? ST_USERDIR
: ST_FILE
;
145 len
= dir
->FileIdentifierLength
;
146 cp
= &dir
->FileIdentifier
[0];
149 memset(&fib
->fib_Date
, 0, sizeof(fib
->fib_Date
));
150 fib
->fib_DirEntryType
= ST_USERDIR
;
151 len
= il
->il_PathTable
->DirectoryIdentifierLength
;
152 cp
= &il
->il_PathTable
->DirectoryIdentifier
[0];
155 if (len
> MAXFILENAMELENGTH
-2)
156 len
= MAXFILENAMELENGTH
-2;
157 for (i
= 0; i
< len
; i
++) {
158 /* Goddam VMS guys screwing up a perfectly good specification... */
163 fib
->fib_FileName
[i
+ 1] = cp
[i
];
165 fib
->fib_FileName
[0] = len
;
166 fib
->fib_FileName
[len
+1] = 0;
167 fib
->fib_Protection
= FIBF_DELETE
|
177 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
178 fib
->fib_NumBlocks
= (fib
->fib_Size
+ 2047) / 2048;
179 fib
->fib_Comment
[0] = 0;
180 fib
->fib_OwnerUID
= 0;
181 fib
->fib_OwnerGID
= 0;
183 il
->il_ParentExtent
= iparent
;
188 /* Parse RockRidge extensions */
189 i
= ((UBYTE
*)&dir
->FileIdentifier
[dir
->FileIdentifierLength
] -
193 while (i
< (dir
->DirectoryLength
- 3)) {
194 struct rrSystemUse
*rr
= (APTR
)(((UBYTE
*)dir
) + i
);
195 D(bug("%s: RR @%d [%c%c] (%d)\n", __func__
, i
, (AROS_BE2WORD(rr
->Signature
) >> 8) & 0xff, AROS_BE2WORD(rr
->Signature
) & 0xff, rr
->Length
));
196 if (rr
->Length
== 0) {
197 D(bug("%s: Corrupted RR section detected (%d left)\n", __func__
, dir
->DirectoryLength
- i
));
200 switch (AROS_BE2WORD(rr
->Signature
)) {
201 case RR_SystemUse_AS
:
202 if (rr
->Version
== RR_SystemUse_AS_VERSION
) {
203 UBYTE
*data
= &rr
->AS
.Data
[0];
205 /* Amiga System Use area */
206 if (rr
->AS
.Flags
& RR_AS_PROTECTION
) {
207 struct SystemUseASProtection
*ap
= (APTR
)data
;
208 fib
->fib_Protection
= (ap
->User
<< 24) |
210 (ap
->MultiUser
<< 8) |
211 (ap
->Protection
<< 0);
212 data
= (UBYTE
*)&ap
[1];
213 has_Amiga_Protections
= TRUE
;
215 if (rr
->AS
.Flags
& RR_AS_COMMENT
) {
216 struct SystemUseASComment
*ac
= (APTR
)data
;
217 int len
= ac
->Length
;
218 if (len
> (MAXCOMMENTLENGTH
- fib
->fib_Comment
[0])-1) {
219 len
= (MAXCOMMENTLENGTH
- fib
->fib_Comment
[0])-1;
220 CopyMem(&ac
->Comment
[0], &fib
->fib_Comment
[fib
->fib_Comment
[0]+1], len
);
221 fib
->fib_Comment
[0] += len
;
226 case RR_SystemUse_PX
:
227 /* This field is mandatory for Rock Ridge */
228 has_RockRidge
= TRUE
;
230 /* Don't overwrite the Amiga RR protections */
231 if (has_Amiga_Protections
)
233 if (rr
->Version
== RR_SystemUse_PX_VERSION
) {
235 ULONG mode
= isoRead32LM(&rr
->PX
.st_mode
);
236 prot
|= (mode
& S_IXOTH
) ? FIBF_OTR_EXECUTE
: 0;
237 prot
|= (mode
& S_IWOTH
) ? (FIBF_OTR_WRITE
| FIBF_OTR_DELETE
): 0;
238 prot
|= (mode
& S_IROTH
) ? FIBF_OTR_READ
: 0;
239 prot
|= (mode
& S_IXGRP
) ? FIBF_GRP_EXECUTE
: 0;
240 prot
|= (mode
& S_IWGRP
) ? (FIBF_GRP_WRITE
| FIBF_GRP_DELETE
) : 0;
241 prot
|= (mode
& S_IRGRP
) ? FIBF_GRP_READ
: 0;
242 prot
|= (mode
& S_IXUSR
) ? 0 : FIBF_EXECUTE
;
243 prot
|= (mode
& S_IWUSR
) ? 0 : (FIBF_WRITE
| FIBF_DELETE
);
244 prot
|= (mode
& S_IRUSR
) ? 0 : FIBF_READ
;
246 fib
->fib_Protection
= prot
;
247 fib
->fib_OwnerUID
= isoRead32LM(&rr
->PX
.st_uid
);
248 fib
->fib_OwnerGID
= isoRead32LM(&rr
->PX
.st_gid
);
251 case RR_SystemUse_NM
:
252 if (rr
->Version
== RR_SystemUse_NM_VERSION
) {
253 int len
= rr
->Length
- ((UBYTE
*)&rr
->NM
.Content
[0] - (UBYTE
*)rr
);
254 if (len
> (MAXCOMMENTLENGTH
- fib
->fib_FileName
[0])-1) {
255 len
= (MAXCOMMENTLENGTH
- fib
->fib_FileName
[0])-1;
256 CopyMem(&rr
->NM
.Content
[0], &fib
->fib_FileName
[fib
->fib_FileName
[0]+1], len
);
257 fib
->fib_FileName
[0] += len
;
261 case RR_SystemUse_CL
:
262 if (rr
->Version
== RR_SystemUse_CL_VERSION
) {
263 il
->il_Extent
= isoRead32LM(&rr
->CL
.ChildDirectory
);
266 case RR_SystemUse_PL
:
267 if (rr
->Version
== RR_SystemUse_PL_VERSION
) {
268 il
->il_ParentExtent
= isoRead32LM(&rr
->PL
.ParentDirectory
);
271 case RR_SystemUse_RE
:
272 if (rr
->Version
== RR_SystemUse_RE_VERSION
) {
273 /* We must ignore this entry */
277 case RR_SystemUse_TF
:
278 /* TF fields have no use under AROS */
280 case RR_SystemUse_SF
:
281 D(bug("%s: Sparse files are not (yet) supported\n"));
290 /* If RockRidge is detected, the PathTable is
291 * useless to us, due to re-arranged directories.
293 if (has_RockRidge
&& iv
&& iv
->iv_PathTable
.Size
) {
294 FreeVec(iv
->iv_PathTable
.Entry
);
295 FreeVec(iv
->iv_PathTable
.Data
);
296 iv
->iv_PathTable
.Size
= 0;
297 iv
->iv_PathTable
.Entries
= 0;
302 D(fib
->fib_FileName
[fib
->fib_FileName
[0]+1]=0);
304 D(bug("%s: %c Lock %p, 0x%08x: \"%s\", dir size %d\n", __func__
,
305 (fib
->fib_DirEntryType
== 0) ? 'F' : 'D',
308 &il
->il_Public
.cl_FileInfoBlock
.fib_FileName
[1],
309 dir
? dir
->DirectoryLength
: il
->il_PathTable
->DirectoryIdentifierLength
));
310 D(bug("%s: @0x%08x, %d bytes\n", __func__
, il
->il_Extent
, il
->il_Public
.cl_FileInfoBlock
.fib_Size
));
315 static LONG
isoReadDir(struct CDFSVolume
*vol
, struct ISOLock
*ilock
, ULONG extent
, ULONG offset
, ULONG iparent
, ULONG
*size
)
317 struct BCache
*bcache
= vol
->cv_Device
->cd_BCache
;
320 D(struct CDFS
*cdfs
= vol
->cv_CDFSBase
;(void)cdfs
;);
322 D(bug("%s: Extent @0x%08x, offset 0x%03x, parent 0x%08x\n", __func__
, extent
, offset
, iparent
));
324 err
= BCache_Read(bcache
, extent
+ (offset
/ 2048), &buff
);
325 if (err
== RETURN_OK
) {
326 struct isoDirectory
*dir
= (APTR
)&buff
[offset
];
327 if (!isoParseDir(vol
, ilock
, dir
, iparent
))
328 err
= ERROR_OBJECT_WRONG_TYPE
;
330 if (dir
->DirectoryLength
== 0) {
331 err
= ERROR_NO_MORE_ENTRIES
;
334 *size
= dir
->DirectoryLength
;
335 D(bug("%s: pe %d of %d dl %d\n", __func__
, ilock
->il_ParentExtent
, offset
, dir
->DirectoryLength
));
336 if (offset
== 0 && dir
->DirectoryLength
) {
337 offset
= dir
->DirectoryLength
;
338 D(bug("%s: Reading parent dir info at %d\n", __func__
, offset
));
339 dir
= (struct isoDirectory
*)&buff
[offset
];
340 ilock
->il_ParentExtent
= isoRead32LM(&dir
->ExtentLocation
);
342 *size
+= dir
->DirectoryLength
;
351 static LONG
isoFindCmp(struct CDFSVolume
*vol
, struct ISOLock
*ifile
, ULONG extent
, BOOL (*cmp
)(struct ISOLock
*il
, APTR data
), APTR data
)
353 struct ISOVolume
*iv
= vol
->cv_Private
;
360 /* Scan the path table first, if present */
361 for (i
= 0; i
< iv
->iv_PathTable
.Entries
; i
++) {
362 struct isoPathTable
*pt
= iv
->iv_PathTable
.Entry
[i
];
363 if (pt
->ExtentLocation
== extent
) {
365 /* Is the thing we're looking for a subdirectory? */
366 for (j
= 0; j
< iv
->iv_PathTable
.Entries
; j
++) {
367 pt
= iv
->iv_PathTable
.Entry
[j
];
370 ifile
->il_PathTable
= pt
;
371 isoParseDir(vol
, ifile
, NULL
, 0);
372 if (cmp(ifile
, data
))
379 /* Read the self/parent at the begining of the directory */
380 err
= isoReadDir(vol
, &tmp
, extent
, 0, 0, &size
);
381 if (err
!= RETURN_OK
)
386 while (offset
< tmp
.il_Public
.cl_FileInfoBlock
.fib_Size
) {
387 err
= isoReadDir(vol
, ifile
, extent
, offset
, extent
, &size
);
389 if (err
!= ERROR_OBJECT_WRONG_TYPE
) {
390 if (err
!= RETURN_OK
)
393 if (cmp(ifile
, data
))
399 /* Move to next block */
400 if (err
== ERROR_OBJECT_WRONG_TYPE
|| size
== 0 ||
401 (2048 - (offset
% 2048)) < sizeof(struct isoDirectory
) + 2) {
402 offset
= (offset
+ 2048 - 1) & ~(2048 - 1);
415 BOOL
cmp(struct ISOLock
*fl
, APTR data
)
417 struct namecmp
*d
= data
;
418 struct CDFS
*cdfs
= d
->cdfs
;
420 D(bug("%s: file \"%s\"(%d) vs \"%s\"(%d)\n", __func__
,
421 d
->file
, d
->len
, &fl
->il_Public
.cl_FileInfoBlock
.fib_FileName
[1],
422 fl
->il_Public
.cl_FileInfoBlock
.fib_FileName
[0]));
424 return (d
->len
== fl
->il_Public
.cl_FileInfoBlock
.fib_FileName
[0] &&
425 Strnicmp(d
->file
, &fl
->il_Public
.cl_FileInfoBlock
.fib_FileName
[1], d
->len
) == 0);
428 static LONG
isoFindName(struct CDFSVolume
*vol
, struct ISOLock
*ifile
, CONST_STRPTR file
, struct ISOLock
*iparent
)
430 struct namecmp data
= {
431 .cdfs
= vol
->cv_CDFSBase
,
436 return isoFindCmp(vol
, ifile
, iparent
->il_Extent
, cmp
, &data
);
439 static LONG
isoFindExtent(struct CDFSVolume
*vol
, struct ISOLock
*ifile
, ULONG extent
, ULONG parent
)
441 BOOL
cmp(struct ISOLock
*fl
, APTR data
) {
442 ULONG extent
= (ULONG
)(IPTR
)data
;
443 return extent
== fl
->il_Extent
;
446 return isoFindCmp(vol
, ifile
, parent
, cmp
, (APTR
)(IPTR
)extent
);
449 static VOID
isoReadPathTables(struct CDFSVolume
*vol
)
451 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
452 struct BCache
*bcache
= vol
->cv_Device
->cd_BCache
;
453 struct ISOVolume
*iv
= vol
->cv_Private
;
459 if (iv
->iv_PathTable
.Size
== 0)
462 sector
= iv
->iv_PathTable
.Extent
;
463 size
= iv
->iv_PathTable
.Size
;
465 D(bug("%s: Reading path table @0x%08x, %d bytes\n", __func__
, sector
* 2048, size
));
466 data
= AllocVec(size
, MEMF_PUBLIC
);
470 /* Read in the path table */
476 if (tocopy
> bcache
->bc_BlockSize
)
477 tocopy
= bcache
->bc_BlockSize
;
479 err
= BCache_Read(bcache
, sector
, &cp
);
480 if (err
!= RETURN_OK
) {
485 CopyMem(cp
, dp
, tocopy
);
491 /* Count the number of entries in the PathTable */
492 size
= iv
->iv_PathTable
.Size
;
493 iv
->iv_PathTable
.Entries
= 0;
496 UWORD len
= (dp
[0] + 8);
501 iv
->iv_PathTable
.Entries
++;
504 D(bug("%s: %d entries\n", __func__
, iv
->iv_PathTable
.Entries
));
506 if (iv
->iv_PathTable
.Entries
== 0) {
508 iv
->iv_PathTable
.Size
= 0;
512 iv
->iv_PathTable
.Entry
= AllocVec(sizeof(struct isoPathTable
*)*iv
->iv_PathTable
.Entries
, MEMF_PUBLIC
);
513 if (iv
->iv_PathTable
.Entry
== NULL
) {
515 iv
->iv_PathTable
.Size
= 0;
519 iv
->iv_PathTable
.Data
= data
;
521 /* Compute the pathtable offsets */
522 dp
= iv
->iv_PathTable
.Data
;
523 for (i
= 0; i
< iv
->iv_PathTable
.Entries
; i
++) {
524 UWORD len
= (dp
[0] + 8);
527 iv
->iv_PathTable
.Entry
[i
] = (struct isoPathTable
*)dp
;
534 LONG
ISO9660_Mount(struct CDFSVolume
*vol
)
536 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
537 struct BCache
*bcache
= vol
->cv_Device
->cd_BCache
;
538 struct ISOVolume
*iv
;
541 BOOL gotdate
= FALSE
, gotname
= FALSE
;
543 /* Don't mount filesystems with an invalid block size */
544 if (bcache
->bc_BlockSize
!= 2048)
545 return ERROR_NOT_A_DOS_DISK
;
547 iv
= AllocVec(sizeof(*iv
), MEMF_PUBLIC
| MEMF_CLEAR
);
549 return ERROR_NO_FREE_STORE
;
551 /* Check for an ISO9660 volume */
552 for (block
= 16;; block
++) {
553 struct isoVolume
*iso
;
554 err
= BCache_Read(bcache
, block
, (UBYTE
**)&iso
);
555 if (err
!= RETURN_OK
)
558 if (memcmp(iso
->Identifier
,"CD001",5) != 0) {
559 err
= ERROR_NOT_A_DOS_DISK
;
563 if (iso
->Type
== ISO_Volume_Primary
) {
565 struct ISOLock
*il
= &iv
->iv_RootLock
;
566 struct isoDirectory
*dir
= (APTR
)&iso
->Primary
.RootDirectoryEntry
[0];
568 iv
->iv_PathTable
.Size
= isoRead32LM(&iso
->Primary
.PathTableSize
);
569 #if _BYTE_ORDER == _BIG_ENDIAN
570 iv
->iv_PathTable
.Extent
= iso
->Primary
.TypeMPathTable
;
571 #elif _BYTE_ORDER == _LITTLE_ENDIAN
572 iv
->iv_PathTable
.Extent
= iso
->Primary
.TypeLPathTable
;
574 CopyMem(iso
, &iv
->iv_Volume
, sizeof(*iso
));
575 for (i
= 0; i
< 32; i
++) {
576 iv
->iv_Name
[i
+1] = iso
->Primary
.VolumeIdentifier
[i
];
577 if (iv
->iv_Name
[i
+1] == 0)
580 /* Remove trailing spaces from the volume name */
581 while (i
> 0 && iv
->iv_Name
[i
] == ' ') i
--;
583 iv
->iv_Name
[i
+1] = 0;
586 /* Convert from ISO date to DOS Datestamp */
587 ascdate2stamp(&iso
->Primary
.VolumeCreation
, &vol
->cv_DosVolume
.dl_VolumeDate
);
590 isoParseDir(vol
, il
, dir
, 0);
591 isoReadDir(vol
, il
, il
->il_Extent
, 0, 0, NULL
);
592 il
->il_Public
.cl_FileLock
.fl_Volume
= MKB_VOLUME(vol
);
597 if (iso
->Type
== ISO_Volume_Terminator
) {
598 vol
->cv_Private
= iv
;
599 struct ISOLock
*il
= &iv
->iv_RootLock
;
600 struct FileInfoBlock
*fib
= &il
->il_Public
.cl_FileInfoBlock
;
604 iv
->iv_Name
[1] = 'I';
605 iv
->iv_Name
[2] = 'S';
606 iv
->iv_Name
[3] = 'O';
607 iv
->iv_Name
[4] = '0';
610 #ifdef AROS_FAST_BSTR
611 vol
->cv_DosVolume
.dl_Name
= &iv
->iv_Name
[1];
613 vol
->cv_DosVolume
.dl_Name
= MKBADDR(iv
->iv_Name
);
616 struct Library
*DOSBase
;
617 if ((DOSBase
= OpenLibrary("dos.library", 0))) {
618 DateStamp(&vol
->cv_DosVolume
.dl_VolumeDate
);
619 CloseLibrary(DOSBase
);
623 /* We use the Volume as our root lock alias */
624 vol
->cv_DosVolume
.dl_DiskType
= AROS_MAKE_ID('I','S','O',0);
625 vol
->cv_DosVolume
.dl_Lock
= MKB_LOCK(&iv
->iv_RootLock
.il_Public
);
626 vol
->cv_Private
= iv
;
628 fib
->fib_DirEntryType
= ST_ROOT
;
629 CopyMem(AROS_BSTR_ADDR(vol
->cv_DosVolume
.dl_Name
),
630 &fib
->fib_FileName
[1],
631 AROS_BSTR_strlen(vol
->cv_DosVolume
.dl_Name
));
632 fib
->fib_FileName
[0] = AROS_BSTR_strlen(vol
->cv_DosVolume
.dl_Name
);
634 /* Cache the path tables */
635 isoReadPathTables(vol
);
642 vol
->cv_Private
= NULL
;
647 LONG
ISO9660_Unmount(struct CDFSVolume
*vol
)
649 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
651 FreeVec(vol
->cv_Private
);
652 return ERROR_NO_FREE_STORE
;
655 LONG
ISO9660_Locate(struct CDFSVolume
*vol
, struct CDFSLock
*idir
, CONST_STRPTR file
, ULONG mode
, struct CDFSLock
**ifile
)
657 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
658 struct ISOVolume
*iv
= vol
->cv_Private
;
659 struct ISOLock
*fl
, *il
, tl
;
660 CONST_STRPTR path
, rest
;
663 if (mode
!= MODE_OLDFILE
)
664 return ERROR_DISK_WRITE_PROTECTED
;
666 il
= (struct ISOLock
*)idir
;
668 D(bug("%s: 0x%08x: \"%s\"\n", __func__
, il
->il_ParentExtent
, file
));
670 if (idir
->cl_FileInfoBlock
.fib_DirEntryType
!= ST_ROOT
&&
671 idir
->cl_FileInfoBlock
.fib_DirEntryType
!= ST_USERDIR
) {
672 D(bug("%s: \"%s\" is not a directory\n", __func__
, &idir
->cl_FileInfoBlock
.fib_FileName
[1]));
673 return ERROR_OBJECT_WRONG_TYPE
;
676 fl
= AllocVec(sizeof(*fl
), MEMF_PUBLIC
| MEMF_CLEAR
);
678 // Get the actual filename
679 path
= strchr(file
, ':');
681 // Switch to the root directory
682 il
= (struct ISOLock
*)B_LOCK(vol
->cv_DosVolume
.dl_Lock
);
688 while (path
[0] == 0 || path
[0] == '/') {
691 CopyMem(il
, fl
, sizeof(*fl
));
692 *ifile
= &fl
->il_Public
;
697 if (path
[0] == '/') {
701 /* Already at root? */
702 if (il
->il_Public
.cl_FileInfoBlock
.fib_DirEntryType
== ST_ROOT
)
705 ASSERT(il
->il_Public
.cl_FileInfoBlock
.fib_DirEntryType
== ST_USERDIR
);
707 /* Otherwise, move to parent */
708 if (il
->il_PathTable
) {
710 tl
.il_PathTable
= iv
->iv_PathTable
.Entry
[il
->il_PathTable
->ParentDirectory
-1];
711 isoParseDir(vol
, &tl
, NULL
, 0);
715 err
= isoReadDir(vol
, &tl
, il
->il_ParentExtent
, 0, 0, NULL
);
716 if (err
== RETURN_OK
) {
717 /* .. and find its name in its parent */
718 if (tl
.il_Public
.cl_FileInfoBlock
.fib_DirEntryType
!= ST_ROOT
)
719 isoFindExtent(vol
, &tl
, tl
.il_Extent
, tl
.il_ParentExtent
);
729 while (*path
&& (rest
= strchr(path
, '/'))) {
731 TEXT fname
[MAXFILENAMELENGTH
];
733 if ((il
->il_Public
.cl_FileInfoBlock
.fib_DirEntryType
!= ST_USERDIR
) &&
734 (il
->il_Public
.cl_FileInfoBlock
.fib_DirEntryType
!= ST_ROOT
)) {
735 return ERROR_DIR_NOT_FOUND
;
739 if (len
>= MAXFILENAMELENGTH
) {
741 return ERROR_OBJECT_NOT_FOUND
;
744 CopyMem(path
, fname
, len
);
746 D(bug("%s: path=\"%s\" rest=\"%s\" fname=\"%s\"\n",
747 __func__
, path
, rest
, fname
));
749 err
= isoFindName(vol
, fl
, fname
, il
);
750 D(bug("%s:%d isoFindName => %d\n", __func__
, __LINE__
, err
));
751 if (err
!= RETURN_OK
) {
756 CopyMem(fl
, &tl
, sizeof(*fl
));
764 *ifile
= &fl
->il_Public
;
768 err
= isoFindName(vol
, fl
, path
, il
);
769 D(bug("%s:%d isoFindName => %d\n", __func__
, __LINE__
, err
));
770 if (err
== RETURN_OK
) {
771 *ifile
= &fl
->il_Public
;
777 err
= ERROR_NO_FREE_STORE
;
783 VOID
ISO9660_Close(struct CDFSVolume
*vol
, struct CDFSLock
*fl
)
785 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
789 LONG
ISO9660_ExamineNext(struct CDFSVolume
*vol
, struct CDFSLock
*dl
, struct FileInfoBlock
*fib
)
791 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
793 struct ISOLock tl
= {}, *il
= (struct ISOLock
*)dl
;
797 D(bug("%s: Root %p, This %p, DiskKey %d of %d\n", __func__
,
798 &((struct ISOVolume
*)vol
->cv_Private
)->iv_RootLock
, dl
,
799 fib
->fib_DiskKey
, dl
->cl_FileInfoBlock
.fib_Size
));
801 /* Do we have a valid size for this directory? */
802 if (dl
->cl_FileInfoBlock
.fib_Size
== 0) {
803 struct isoDirectory
*dir
;
804 err
= BCache_Read(vol
->cv_Device
->cd_BCache
, il
->il_Extent
, (UBYTE
**)&dir
);
805 if (err
!= RETURN_OK
)
807 dl
->cl_FileInfoBlock
.fib_Size
= isoRead32LM(&dir
->DataLength
);
810 if (fib
->fib_DiskKey
== 0) {
811 /* Skip the first two entries */
812 err
= isoReadDir(vol
, &tl
, il
->il_Extent
, 0, 0, &size
);
813 if (err
!= RETURN_OK
)
815 fib
->fib_DiskKey
= size
;
818 if (fib
->fib_DiskKey
>= dl
->cl_FileInfoBlock
.fib_Size
) {
819 D(bug("%s: No more entries (%d >= %d)\n", __func__
, fib
->fib_DiskKey
, dl
->cl_FileInfoBlock
.fib_Size
));
820 return ERROR_NO_MORE_ENTRIES
;
823 offset
= fib
->fib_DiskKey
;
825 while (offset
< dl
->cl_FileInfoBlock
.fib_Size
) {
826 err
= isoReadDir(vol
, &tl
, il
->il_Extent
, offset
, il
->il_Extent
, &size
);
828 if (err
!= RETURN_OK
&& err
!= ERROR_OBJECT_WRONG_TYPE
)
831 D(bug("%s: err=%d, size=%d\n", __func__
, err
, size
));
834 /* Move to next block */
835 if (err
== ERROR_OBJECT_WRONG_TYPE
|| size
== 0 ||
836 (2048 - (offset
% 2048)) < sizeof(struct isoDirectory
) + 2) {
837 offset
= (offset
+ 2048 - 1) & ~(2048 - 1);
840 if (err
== RETURN_OK
) {
841 struct FileInfoBlock
*tfib
= &tl
.il_Public
.cl_FileInfoBlock
;
842 CopyMem(tfib
, fib
, sizeof(*fib
));
846 err
= ERROR_NO_MORE_ENTRIES
;
849 fib
->fib_DiskKey
= offset
;
851 D(bug("%s: Error %d\n", __func__
, err
));
856 LONG
ISO9660_Read(struct CDFSVolume
*vol
, struct CDFSLock
*fl
, APTR buff
, SIPTR len
, SIPTR
*actualp
)
858 struct CDFS
*cdfs
= vol
->cv_CDFSBase
;
859 struct BCache
*bcache
= vol
->cv_Device
->cd_BCache
;
860 struct ISOLock
*il
= (struct ISOLock
*)fl
;
861 UQUAD size
= fl
->cl_FileInfoBlock
.fib_Size
;
864 LONG err
= RETURN_OK
;
868 block
= il
->il_Offset
/ 2048;
869 offset
= il
->il_Offset
% 2048;
870 if ((len
+ il
->il_Offset
) > size
)
871 len
= size
- il
->il_Offset
;
874 ULONG tocopy
= 2048 - offset
;
878 err
= BCache_Read(bcache
, il
->il_Extent
+ block
, &cache
);
879 if (err
!= RETURN_OK
)
881 CopyMem(cache
+ offset
, buff
, tocopy
);
886 il
->il_Offset
+= tocopy
;
896 LONG
ISO9660_Seek(struct CDFSVolume
*vol
, struct CDFSLock
*fl
, SIPTR pos
, LONG mode
, SIPTR
*oldpos
)
898 struct ISOLock
*il
= (struct ISOLock
*)fl
;
899 UQUAD size
= fl
->cl_FileInfoBlock
.fib_Size
;
901 *oldpos
= il
->il_Offset
;
903 case OFFSET_BEGINNING
:
904 if (pos
< 0 || pos
> size
)
905 return ERROR_SEEK_ERROR
;
909 if (-pos
> il
->il_Offset
||
910 (il
->il_Offset
+ pos
) > size
)
911 return ERROR_SEEK_ERROR
;
912 il
->il_Offset
+= pos
;
915 if (pos
< 0 || -pos
> size
)
916 return ERROR_SEEK_ERROR
;
917 il
->il_Offset
= size
+ pos
;
920 return ERROR_SEEK_ERROR
;
926 const struct CDFSOps ISO9660_Ops
= {
927 .op_Type
= AROS_MAKE_ID('I','S','O',0),
928 .op_Mount
= ISO9660_Mount
,
929 .op_Unmount
= ISO9660_Unmount
,
930 .op_Locate
= ISO9660_Locate
,
931 .op_Close
= ISO9660_Close
,
932 .op_ExamineNext
= ISO9660_ExamineNext
,
933 .op_Seek
= ISO9660_Seek
,
934 .op_Read
= ISO9660_Read
,