PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
cdfs_iop.c
1#include <stdio.h>
2#include <libcdvd-common.h>
3#include <sysclib.h>
4#include <sysmem.h>
5
6#include "cdfs_iop.h"
7
8#define TRUE 1
9#define FALSE 0
10
11#define MAX_DIR_CACHE_SECTORS 32
12
14{
15 short length;
16 unsigned int fileLBA;
17 unsigned int fileLBA_bigend;
18 unsigned int fileSize;
19 unsigned int fileSize_bigend;
20 unsigned char dateStamp[6];
21 unsigned char reserved1;
22 unsigned char fileProperties;
23 unsigned char reserved2[6];
24 unsigned char filenameLength;
25 char filename[128];
26} __attribute__((packed)); // This is the internal format on the CD
27// a file with a single character filename will have a 34byte toc entry
28// (max 60 entries per sector)6
29
30// TocEntry structure contains only the important stuff needed for export
31//
32
34{
35 char pathname[1024]; // The pathname of the cached directory
36 unsigned int valid; // TRUE if cache data is valid, FALSE if not
37
38 unsigned int path_depth; // The path depth of the cached directory (0 = root)
39
40 unsigned int sector_start; // The start sector (LBA) of the cached directory
41 unsigned int sector_num; // The total size of the directory (in sectors)
42 unsigned int cache_offset; // The offset from sector_start of the cached area
43 unsigned int cache_size; // The size of the cached directory area (in sectors)
44
45 u8 *cache; // The actual cached data
46};
47
49{
50 u16 length;
51 u32 tocLBA;
52 u32 tocLBA_bigend;
53 u32 tocSize;
54 u32 tocSize_bigend;
55 u8 dateStamp[8];
56 u8 reserved[6];
57 u8 reserved2;
58 u8 reserved3;
59} __attribute__((packed));
60
62{
63 char year[4];
64 char month[2];
65 char day[2];
66 char hours[2];
67 char minutes[2];
68 char seconds[2];
69 char hundreths[2];
70 char terminator[1];
71} __attribute__((packed));
72
74{
75 u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL
76 u8 volID[5]; // "CD001"
77 u8 reserved2;
78 u8 reserved3;
79 u8 sysIdName[32];
80 u8 volName[32]; // The ISO9660 Volume Name
81 u8 reserved5[8];
82 u32 volSize; // Volume Size
83 u32 volSizeBig; // Volume Size Big-Endian
84 u8 reserved6[32];
85 u32 unknown1;
86 u32 unknown1_bigend;
87 u16 volDescSize;
88 u16 volDescSize_bigend;
89 u32 unknown3;
90 u32 unknown3_bigend;
91 u32 priDirTableLBA; // LBA of Primary Dir Table
92 u32 reserved7;
93 u32 secDirTableLBA; // LBA of Secondary Dir Table
94 u32 reserved8;
95 struct RootDirTocHeader rootToc;
96 u8 volSetName[128];
97 u8 publisherName[128];
98 u8 preparerName[128];
99 u8 applicationName[128];
100 u8 copyrightFileName[37];
101 u8 abstractFileName[37];
102 u8 bibliographyFileName[37];
103 struct ASCIIDate creationDate;
104 struct ASCIIDate modificationDate;
105 struct ASCIIDate effectiveDate;
106 struct ASCIIDate expirationDate;
107 u8 reserved10;
108 u8 reserved11[1166];
109} __attribute__((packed));
110
111enum Cache_getMode {
112 CACHE_START = 0,
113 CACHE_NEXT = 1
114};
115
116enum PathMatch {
117 NOT_MATCH = 0,
118 MATCH,
119 SUBDIR
120};
121
122static struct CacheInfoDir cacheInfoDir;
123static struct CDVolDesc cdVolDesc;
124static sceCdRMode cdReadMode;
125static u8 dvdvBuffer[2064];
126
127static int cdvdChangedMagic = 0;
128static int cdvdChangedMagicLast[CHANGED_MAX] = {-1};
129
130/***********************************************
131* *
132* PRIVATE FUNCTIONS *
133* *
134***********************************************/
135
136// Used in findfile
137static int strcasecmp(const char *s1, const char *s2) {
138 while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) {
139 s1++;
140 s2++;
141 }
142
143 return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
144}
145
146/***********************************************
147* Determines if there is a valid disc inserted *
148***********************************************/
149static int isValidDisc(void) {
150 int result;
151
152 switch (sceCdGetDiskType()) {
153 case SCECdPSCD:
154 case SCECdPSCDDA:
155 case SCECdPS2CD:
156 case SCECdPS2CDDA:
157 case SCECdPS2DVD:
158 case SCECdDVDV:
159 result = 1;
160 break;
161 default:
162 result = 0;
163 }
164
165 return result;
166}
167
168// Copy a TOC Entry from the CD native format to our tidier format
169static void copyToTocEntry(struct TocEntry *tocEntry, struct DirTocEntry *internalTocEntry) {
170 int filenamelen;
171
172 DPRINTF("copyToTocEntry: from=%p, to=%p\n\n", tocEntry, internalTocEntry);
173 DPRINTF("copyToTocEntry: DirTocEntry=%p\n", internalTocEntry);
174 DPRINTF(" length......... %hd\n", internalTocEntry->length);
175 DPRINTF(" fileLBA........ %u\n", internalTocEntry->fileLBA);
176 DPRINTF(" fileLBA_bigend. %u\n", internalTocEntry->fileLBA_bigend);
177 DPRINTF(" fileSize....... %u\n", internalTocEntry->fileSize);
178 DPRINTF(" fileSize_bigend %u\n", internalTocEntry->fileSize_bigend);
179 DPRINTF(" dateStamp...... %s\n", internalTocEntry->dateStamp);
180 DPRINTF(" reserved1...... %u\n", internalTocEntry->reserved1);
181 DPRINTF(" fileProperties. %u\n", internalTocEntry->fileProperties);
182 DPRINTF(" reserved2...... %s\n", internalTocEntry->reserved2);
183 DPRINTF(" filenameLength. %u\n", internalTocEntry->filenameLength);
184 DPRINTF(" filename....... %s\n", internalTocEntry->filename);
185
186 tocEntry->fileSize = internalTocEntry->fileSize;
187 tocEntry->fileLBA = internalTocEntry->fileLBA;
188 tocEntry->fileProperties = internalTocEntry->fileProperties;
189
190 if (cdVolDesc.filesystemType == 2) {
191 int i;
192
193 // This is a Joliet Filesystem, so use Unicode to ISO string copy
194 filenamelen = internalTocEntry->filenameLength / 2;
195
196 for (i = 0; i < filenamelen; i++)
197 tocEntry->filename[i] = internalTocEntry->filename[(i << 1) + 1];
198 } else {
199 filenamelen = internalTocEntry->filenameLength;
200
201 // use normal string copy
202 strncpy(tocEntry->filename, internalTocEntry->filename, 128);
203 }
204
205 tocEntry->filename[filenamelen] = 0;
206
207 if (!(tocEntry->fileProperties & 0x02)) {
208 // strip the ;1 from the filename (if it's there)
209 strtok(tocEntry->filename, ";");
210 }
211
212 DPRINTF("copyToTocEntry: tocEntry=%p\n\n", tocEntry);
213 DPRINTF(" fileLBA........ %u\n\n", tocEntry->fileLBA);
214 DPRINTF(" fileSize....... %u\n\n", tocEntry->fileSize);
215 DPRINTF(" filename....... %s\n\n", tocEntry->filename);
216 DPRINTF(" fileProperties. %u\n\n", tocEntry->fileProperties);
217}
218
219
220// findPath should use the current directory cache to start it's search (in this case the root)
221// and should change cacheInfoDir.pathname, to the path of the dir it finds
222// it should also cache the first chunk of directory sectors,
223// and fill the contents of the other elements of cacheInfoDir appropriately
224
225static int findPath(char *pathname) {
226 char *dirname;
227 char *seperator;
228
229
230 struct TocEntry localTocEntry;
231
232 dirname = strtok(pathname, "\\/");
233 DPRINTF("findPath: trying to find directory %s\n\n", pathname);
234
235 if (!isValidDisc())
236 return FALSE;
237
239
240 while (dirname != NULL) {
241 int dir_entry;
242 int found_dir;
243
244 struct DirTocEntry *tocEntryPointer;
245
246 found_dir = FALSE;
247
248 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
249
250 // Always skip the first entry (self-refencing entry)
251 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
252
253 dir_entry = 0;
254
255 for (; tocEntryPointer < (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048)); tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
256 // If we have a null toc entry, then we've either reached the end of the dir, or have reached a sector boundary
257 if (tocEntryPointer->length == 0) {
258 DPRINTF("Got a null pointer entry, so either reached end of dir, or end of sector\n\n");
259 tocEntryPointer = (struct DirTocEntry *)(cacheInfoDir.cache + (((((u8 *)tocEntryPointer - cacheInfoDir.cache) / 2048) + 1) * 2048));
260 }
261
262 if (tocEntryPointer >= (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048))) {
263 // If we've gone past the end of the cache
264 // then check if there are more sectors to load into the cache
265
266 if ((cacheInfoDir.cache_offset + cacheInfoDir.cache_size) < cacheInfoDir.sector_num) {
267 // If there are more sectors to load, then load them
268 cacheInfoDir.cache_offset += cacheInfoDir.cache_size;
269 cacheInfoDir.cache_size = cacheInfoDir.sector_num - cacheInfoDir.cache_offset;
270
271 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
272 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
273
274 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
275 DPRINTF("Couldn't Read from CD !\n\n");
276 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read time?
277 return FALSE;
278 }
279
280 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
281 } else {
282 cacheInfoDir.valid = FALSE;
283 return FALSE;
284 }
285 }
286
287 // If the toc Entry is a directory ...
288 if (tocEntryPointer->fileProperties & 0x02) {
289 // Convert to our format (inc ascii name), for the check
290 copyToTocEntry(&localTocEntry, tocEntryPointer);
291
292 // If it's the link to the parent directory, then give it the name ".."
293 if (dir_entry == 0) {
294 if (cacheInfoDir.path_depth != 0) {
295 DPRINTF("First directory entry in dir, so name it '..'\n\n");
296 strcpy(localTocEntry.filename, "..");
297 }
298 }
299
300 // Check if this is the directory that we are looking for
301 if (strcasecmp(dirname, localTocEntry.filename) == 0) {
302 DPRINTF("Found the matching sub-directory\n\n");
303 found_dir = TRUE;
304
305 if (dir_entry == 0) {
306 // We've matched with the parent directory
307 // so truncate the pathname by one level
308
309 if (cacheInfoDir.path_depth > 0)
310 cacheInfoDir.path_depth--;
311
312 if (cacheInfoDir.path_depth == 0) {
313 // If at root then just clear the path to root
314 // (simpler than finding the colon seperator etc)
315 cacheInfoDir.pathname[0] = 0;
316 } else {
317 seperator = strrchr(cacheInfoDir.pathname, '/');
318
319 if (seperator != NULL)
320 *seperator = 0;
321 }
322 } else {
323 // otherwise append a seperator, and the matched directory
324 // to the pathname
325 strcat(cacheInfoDir.pathname, "/");
326 DPRINTF("Adding '%s' to cached pathname - path depth = %u\n\n", dirname, cacheInfoDir.path_depth);
327 strcat(cacheInfoDir.pathname, dirname);
328 cacheInfoDir.path_depth++;
329 }
330
331 // Exit out of the search loop
332 // (and find the next sub-directory, if there is one)
333 break;
334 } else {
335 DPRINTF("Found a directory, but it doesn't match\n\n");
336 }
337 }
338
339 dir_entry++;
340
341 } // end of cache block search loop
342
343
344 // if we've reached here, without finding the directory, then it's not there
345 if (!found_dir) {
346 cacheInfoDir.valid = FALSE;
347 return FALSE;
348 }
349
350 // find name of next dir
351 dirname = strtok(NULL, "\\/");
352
353 cacheInfoDir.sector_start = localTocEntry.fileLBA;
354 cacheInfoDir.sector_num = (localTocEntry.fileSize >> 11) + ((cdVolDesc.rootToc.tocSize & 2047) != 0);
355
356 // Cache the start of the found directory
357 // (used in searching if this isn't the last dir,
358 // or used by whatever requested the cache in the first place if it is the last dir)
359 cacheInfoDir.cache_offset = 0;
360 cacheInfoDir.cache_size = cacheInfoDir.sector_num;
361
362 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
363 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
364
365 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
366 DPRINTF("Couldn't Read from CD, trying to read %u sectors, starting at sector %u !\n\n",
367 cacheInfoDir.cache_size, cacheInfoDir.sector_start + cacheInfoDir.cache_offset);
368 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read time?
369 return FALSE;
370 }
371 }
372
373// If we've got here then we found the requested directory
374 DPRINTF("findPath found the path\n\n");
375 cacheInfoDir.valid = TRUE;
376 return TRUE;
377}
378
379static int cdfs_getVolumeDescriptor(void) {
380 // Read until we find the last valid Volume Descriptor
381 int volDescSector;
382 static struct CDVolDesc localVolDesc;
383 DPRINTF("cdfs_getVolumeDescriptor called\n\n");
384
385 for (volDescSector = 16; volDescSector < 20; volDescSector++) {
386 cdfs_readSect(volDescSector, 1, (u8*)&localVolDesc);
387
388 // If this is still a volume Descriptor
389 if (memcmp(localVolDesc.volID, "CD001", 5) == 0) {
390 if ((localVolDesc.filesystemType == 1) ||
391 (localVolDesc.filesystemType == 2)) {
392 memcpy(&cdVolDesc, &localVolDesc, sizeof(struct CDVolDesc));
393 }
394 } else
395 break;
396 }
397
398#ifdef DEBUG
399 switch (cdVolDesc.filesystemType) {
400 case 1:
401 DPRINTF("CD FileSystem is ISO9660\n\n");
402 break;
403 case 2:
404 DPRINTF("CD FileSystem is Joliet\n\n");
405 break;
406 default:
407 DPRINTF("CD FileSystem is unknown type\n\n");
408 break;
409 }
410#endif
411 // sceCdStop();
412 return TRUE;
413}
414
415static enum PathMatch comparePath(const char *path) {
416 int length;
417 int i;
418
419 length = strlen(cacheInfoDir.pathname);
420
421 for (i = 0; i < length; i++) {
422 // check if character matches
423 if (path[i] != cacheInfoDir.pathname[i]) {
424 // if not, then is it just because of different path seperator ?
425 if ((path[i] == '/') || (path[i] == '\\')) {
426 if ((cacheInfoDir.pathname[i] == '/') || (cacheInfoDir.pathname[i] == '\\')) {
427 continue;
428 }
429 }
430
431 // if the characters don't match for any other reason then report a failure
432 return NOT_MATCH;
433 }
434 }
435
436 // Reached the end of the Cached pathname
437 // if requested path is same length, then report exact match
438 if (path[length] == 0)
439 return MATCH;
440
441 // if requested path is longer, and next char is a dir seperator
442 // then report sub-dir match
443 if ((path[length] == '/') || (path[length] == '\\'))
444 return SUBDIR;
445 else
446 return NOT_MATCH;
447}
448
449// Find, and cache, the requested directory, for use by GetDir or (and thus open)
450// provide an optional offset variable, for use when caching dirs of greater than 500 files
451
452// returns TRUE if all TOC entries have been retrieved, or
453// returns FALSE if there are more TOC entries to be retrieved
454static int cdfs_cacheDir(const char *pathname, enum Cache_getMode getMode) {
455 // macke sure that the requested pathname is not directly modified
456 static char dirname[1024];
457
458 DPRINTF("Attempting to find, and cache, directory: %s\n", pathname);
459
460 // Invalidate table of contents cache if disk changed
461 if (cdfs_checkDiskChanged(CHANGED_TOC)) {
462 cacheInfoDir.valid = FALSE;
463 }
464
465 // only take any notice of the existing cache, if it's valid
466 if (cacheInfoDir.valid) {
467 // Check if the requested path is already cached
468 // if (strcasecmp(pathname,cacheInfoDir.pathname)==0)
469 if (comparePath(pathname) == MATCH) {
470 DPRINTF("CacheDir: The requested path is already cached\n");
471 // If so, is the request ot cache the start of the directory, or to resume the next block ?
472 if (getMode == CACHE_START) {
473 DPRINTF(" and requested cache from start of dir\n");
474
475 if (cacheInfoDir.cache_offset == 0) {
476// requested cache of start of the directory, and thats what's already cached
477// so sit back and do nothing
478 DPRINTF(" and start of dir is already cached so nothing to do :o)\n");
479
480 cacheInfoDir.valid = TRUE;
481 return TRUE;
482 } else {
483// Requested cache of start of the directory, but thats not what's cached
484// so re-cache the start of the directory
485 DPRINTF(" but dir isn't cached from start, so re-cache existing dir from start\n");
486
487 // reset cache data to start of existing directory
488 cacheInfoDir.cache_offset = 0;
489 cacheInfoDir.cache_size = cacheInfoDir.sector_num;
490
491 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
492 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
493
494 // Now fill the cache with the specified sectors
495 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
496 DPRINTF("Couldn't Read from CD !\n");
497
498 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read first time?
499 return FALSE;
500 }
501
502 cacheInfoDir.valid = TRUE;
503 return TRUE;
504 }
505 } else {
506 // getMode == CACHE_NEXT
507 // So get the next block of the existing directory
508 cacheInfoDir.cache_offset += cacheInfoDir.cache_size;
509 cacheInfoDir.cache_size = cacheInfoDir.sector_num - cacheInfoDir.cache_offset;
510
511 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
512 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
513
514 // Now fill the cache with the specified sectors
515 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
516 DPRINTF("Couldn't Read from CD !\n");
517
518 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read first time?
519 return FALSE;
520 }
521
522 cacheInfoDir.valid = TRUE;
523 return TRUE;
524 }
525 } else {
526 // requested directory is not the cached directory (but cache is still valid)
527 DPRINTF("Cache is valid, but cached directory, is not the requested one\n"
528 "so check if the requested directory is a sub-dir of the cached one\n");
529 DPRINTF("Requested Path = %s , Cached Path = %s\n", pathname, cacheInfoDir.pathname);
530
531 if (comparePath(pathname) == SUBDIR) {
532 int path_len;
533
534// If so then we can start our search for the path, from the currently cached directory
535 DPRINTF("Requested dir is a sub-dir of the cached directory,\n"
536 "so start search from current cached dir\n");
537 // if the cached chunk, is not the start of the dir,
538 // then we will need to re-load it before starting search
539 if (cacheInfoDir.cache_offset != 0) {
540 cacheInfoDir.cache_offset = 0;
541 cacheInfoDir.cache_size = cacheInfoDir.sector_num;
542 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
543 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
544
545 // Now fill the cache with the specified sectors
546 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
547 DPRINTF("Couldn't Read from CD !\n");
548 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read time?
549 return FALSE;
550 }
551 }
552
553 // start the search, with the path after the current directory
554 path_len = strlen(cacheInfoDir.pathname);
555 strcpy(dirname, pathname + path_len);
556
557 // findPath should use the current directory cache to start it's search
558 // and should change cacheInfoDir.pathname, to the path of the dir it finds
559 // it should also cache the first chunk of directory sectors,
560 // and fill the contents of the other elements of cacheInfoDir appropriately
561
562 return (findPath(dirname));
563 }
564 }
565 }
566
567// If we've got here, then either the cache was not valid to start with
568// or the requested path is not a subdirectory of the currently cached directory
569// so lets start again
570 DPRINTF("The cache is not valid, or the requested directory is not a sub-dir of the cached one\n\n");
571
572 if (!isValidDisc()) {
573 DPRINTF("No supported disc inserted.\n");
574 return -1;
575 }
576
578
579 // Read the main volume descriptor
580 if (!cdfs_getVolumeDescriptor()) {
581 DPRINTF("Could not read the CD/DVD Volume Descriptor\n");
582 return -1;
583 }
584
585 DPRINTF("Read the CD Volume Descriptor\n\n");
586
587 cacheInfoDir.path_depth = 0;
588 strcpy(cacheInfoDir.pathname, "");
589
590 // Setup the lba and sector size, for retrieving the root toc
591 cacheInfoDir.cache_offset = 0;
592 cacheInfoDir.sector_start = cdVolDesc.rootToc.tocLBA;
593 cacheInfoDir.sector_num = (cdVolDesc.rootToc.tocSize >> 11) + ((cdVolDesc.rootToc.tocSize & 2047) != 0);
594 cacheInfoDir.cache_size = cacheInfoDir.sector_num;
595
596 if (cacheInfoDir.cache_size > MAX_DIR_CACHE_SECTORS)
597 cacheInfoDir.cache_size = MAX_DIR_CACHE_SECTORS;
598
599 // Now fill the cache with the specified sectors
600 if (!cdfs_readSect(cacheInfoDir.sector_start + cacheInfoDir.cache_offset, cacheInfoDir.cache_size, cacheInfoDir.cache)) {
601 DPRINTF("Couldn't Read from CD !\n");
602 cacheInfoDir.valid = FALSE; // should we completely invalidate just because we couldnt read time?
603 return FALSE;
604 }
605
606 DPRINTF("Read the first block from the root directory\n");
607 DPRINTF("Calling findPath\n");
608 strcpy(dirname, pathname);
609
610 return (findPath(dirname));
611}
612
613static void splitPath(const char *constpath, char *dir, char *fname) {
614 // 255 char max path-length is an ISO9660 restriction
615 // we must change this for Joliet or relaxed iso restriction support
616 static char pathcopy[1024 + 1];
617 char *slash;
618
619 strncpy(pathcopy, constpath, 1024);
620 slash = strrchr(pathcopy, '/');
621
622 // if the path doesn't contain a '/' then look for a '\'
623 if (!slash)
624 slash = strrchr(pathcopy, (int)'\\');
625
626 // if a slash was found
627 if (slash != NULL) {
628 // null terminate the path
629 slash[0] = 0;
630 // and copy the path into 'dir'
631 strncpy(dir, pathcopy, 1024);
632 dir[255] = 0;
633
634 // copy the filename into 'fname'
635 strncpy(fname, slash + 1, 128);
636 fname[128] = 0;
637 } else {
638 dir[0] = 0;
639
640 strncpy(fname, pathcopy, 128);
641 fname[128] = 0;
642 }
643}
644
645/***********************************************
646* *
647* CDFS FUNCTIONS *
648* *
649***********************************************/
650
651int cdfs_prepare(void) {
652
653 // Initialise the directory cache
654 strcpy(cacheInfoDir.pathname, ""); // The pathname of the cached directory
655 cacheInfoDir.valid = FALSE; // Cache is not valid
656 cacheInfoDir.path_depth = 0; // 0 = root)
657 cacheInfoDir.sector_start = 0; // The start sector (LBA) of the cached directory
658 cacheInfoDir.sector_num = 0; // The total size of the directory (in sectors)
659 cacheInfoDir.cache_offset = 0; // The offset from sector_start of the cached area
660 cacheInfoDir.cache_size = 0; // The size of the cached directory area (in sectors)
661
662 if (cacheInfoDir.cache == NULL)
663 cacheInfoDir.cache = (u8 *)AllocSysMemory(0, MAX_DIR_CACHE_SECTORS * 2048, NULL);
664
665 // setup the cdReadMode structure
666 cdReadMode.trycount = 0;
667 cdReadMode.spindlctrl = SCECdSpinStm;
668 cdReadMode.datapattern = SCECdSecS2048;
669
670 return 0;
671}
672
673int cdfs_start(void) {
674 return sceCdInit(SCECdINoD);
675}
676
677int cdfs_finish(void) {
678 if (cacheInfoDir.cache)
679 FreeSysMemory(cacheInfoDir.cache);
680
681 return 0;
682}
683
684int cdfs_findfile(const char *fname, struct TocEntry *tocEntry) {
685 static char filename[128 + 1];
686 static char pathname[1024 + 1];
687
688 struct DirTocEntry *tocEntryPointer;
689
690 DPRINTF("cdfs_findfile called\n\n");
691
692 splitPath(fname, pathname, filename);
693 DPRINTF("Trying to find file: %s in directory: %s\n", filename, pathname);
694
695 // Invalidate table of contents cache if disk changed
696 if (cdfs_checkDiskChanged(CHANGED_TOC)) {
697 cacheInfoDir.valid = FALSE;
698 }
699
700 if ((cacheInfoDir.valid) && (comparePath(pathname) == MATCH)) {
701 // the directory is already cached, so check through the currently
702 // cached chunk of the directory first
703
704 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
705
706 for (; tocEntryPointer < (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048)); tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
707 if (tocEntryPointer->length == 0) {
708 DPRINTF("Got a null pointer entry, so either reached end of dir, or end of sector\n");
709 tocEntryPointer = (struct DirTocEntry *)(cacheInfoDir.cache + (((((u8 *)tocEntryPointer - cacheInfoDir.cache) / 2048) + 1) * 2048));
710 }
711
712 if (tocEntryPointer >= (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048))) {
713 // reached the end of the cache block
714 break;
715 }
716
717 copyToTocEntry(tocEntry, tocEntryPointer);
718
719 if (strcasecmp(tocEntry->filename, filename) == 0) {
720 // and it matches !!
721 return TRUE;
722 }
723 } // end of for loop
724
725 // If that was the only dir block, and we havent found it, then fail
726 if (cacheInfoDir.cache_size == cacheInfoDir.sector_num)
727 return FALSE;
728
729 // Otherwise there is more dir to check
730 if (cacheInfoDir.cache_offset == 0) {
731 // If that was the first block then continue with the next block
732 if (!cdfs_cacheDir(pathname, CACHE_NEXT))
733 return FALSE;
734 } else {
735 // otherwise (if that wasnt the first block) then start checking from the start
736 if (!cdfs_cacheDir(pathname, CACHE_START))
737 return FALSE;
738 }
739 } else {
740 DPRINTF("Trying to cache directory\n\n");
741 // The wanted directory wasnt already cached, so cache it now
742 if (!cdfs_cacheDir(pathname, CACHE_START)) {
743 DPRINTF("Failed to cache directory\n\n");
744 return FALSE;
745 }
746 }
747
748 // If we've got here, then we have a block of the directory cached, and want to check
749 // from this point, to the end of the dir
750 DPRINTF("cache_size = %u\n", cacheInfoDir.cache_size);
751 while (cacheInfoDir.cache_size > 0) {
752 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
753
754 if (cacheInfoDir.cache_offset == 0)
755 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
756
757 for (; tocEntryPointer < (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048)); tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
758 if (tocEntryPointer->length == 0) {
759 DPRINTF("Got a null pointer entry, so either reached end of dir, or end of sector\n");
760 DPRINTF("Offset into cache = %d bytes\n", (int)((u8 *)tocEntryPointer - cacheInfoDir.cache));
761 tocEntryPointer = (struct DirTocEntry *)(cacheInfoDir.cache + (((((u8 *)tocEntryPointer - cacheInfoDir.cache) / 2048) + 1) * 2048));
762 }
763
764 if (tocEntryPointer >= (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048))) {
765 // reached the end of the cache block
766 break;
767 }
768
769 copyToTocEntry(tocEntry, tocEntryPointer);
770
771 if (strcasecmp(tocEntry->filename, filename) == 0) {
772 DPRINTF("Found a matching file\n\n");
773 // and it matches !!
774 return TRUE;
775 }
776
777 DPRINTF("Non-matching file - looking for %s , found %s\n", filename, tocEntry->filename);
778 } // end of for loop
779
780 DPRINTF("Reached end of cache block\n");
781 // cache the next block
782 cdfs_cacheDir(pathname, CACHE_NEXT);
783 }
784
785 // we've run out of dir blocks to cache, and still not found it, so fail
786 DPRINTF("cdfs_findfile: could not find file\n");
787 return FALSE;
788}
789
790/********************
791* Optimised CD Read *
792********************/
793
794int cdfs_readSect(u32 lsn, u32 sectors, u8 *buf) {
795 u32 i;
796 u32 consecutive_sectors = (sectors > 2) ? (sectors * 2048) / 2064 : 0;
797 int retry;
798 int result = 0;
799 cdReadMode.trycount = 32;
800
801 for (retry = 0; retry < 32; retry++) { // 32 retries
802 if (retry <= 8)
803 cdReadMode.spindlctrl = 1; // Try fast reads for first 8 tries
804 else
805 cdReadMode.spindlctrl = 0; // Then try slow reads
806
807 if (!isValidDisc())
808 return FALSE;
809
811
813 {
814 if (consecutive_sectors > 0)
815 {
816 result = !sceCdReadDVDV(lsn, consecutive_sectors, buf, &cdReadMode);
817 if (result == 0)
818 {
819 sceCdSync(0);
820 result = sceCdGetError();
821 }
822 if (result != 0)
823 {
824 continue;
825 }
826 }
827 for (i = 0; i < consecutive_sectors; i += 1)
828 {
829 memmove(buf + (2048 * i), buf + (2064 * i) + 12, 2048);
830 }
831 for (i = consecutive_sectors; i < sectors; i += 1)
832 {
833 result = !sceCdReadDVDV(lsn + i, 1, dvdvBuffer, &cdReadMode);
834 if (result == 0)
835 {
836 sceCdSync(0);
837 result = sceCdGetError();
838 }
839 if (result != 0)
840 {
841 break;
842 }
843 memcpy(buf + (2048 * i), dvdvBuffer + 12, 2048);
844 }
845 }
846 else
847 {
848 result = !sceCdRead(lsn, sectors, buf, &cdReadMode);
849 if (result == 0)
850 {
851 sceCdSync(0);
852 result = sceCdGetError();
853 }
854 }
855
856 if (result == 0)
857 break;
858 }
859
860 cdReadMode.trycount = 32;
861 cdReadMode.spindlctrl = 1;
862
863 if (result == 0)
864 return TRUE;
865
866 memset(buf, 0, (sectors << 11));
867
868 return FALSE; // error
869}
870
871int cdfs_getDir(const char *pathname, struct TocEntry tocEntry[], unsigned int req_entries) {
872 int matched_entries;
873 int dir_entry;
874
875 struct TocEntry localTocEntry;
876 struct DirTocEntry *tocEntryPointer;
877
878 DPRINTF("cdfs_getDir Request\n\n");
879
880 matched_entries = 0;
881
882 // pre-cache the dir (and get the new pathname - in-case selected "..")
883 if (!cdfs_cacheDir(pathname, CACHE_START)) {
884 DPRINTF("cdfs_getDir - Call of cdfs_cacheDir failed\n\n");
885 return -1;
886 }
887
888 DPRINTF("requested directory is %u sectors\n", cacheInfoDir.sector_num);
889
890 // Cache the start of the requested directory
891 if (!cdfs_cacheDir(cacheInfoDir.pathname, CACHE_START)) {
892 DPRINTF("cdfs_getDir - Call of cdfs_cacheDir failed\n\n");
893 return -1;
894 }
895
896 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
897 // skip the first self-referencing entry
898 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
899
900 // skip the parent entry if this is the root
901 if (cacheInfoDir.path_depth == 0)
902 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
903
904 dir_entry = 0;
905
906 while (1) {
907 DPRINTF("cdfs_getDir - inside while-loop\n\n");
908
909 // parse the current cache block
910 for (; tocEntryPointer < (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048)); tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
911 if (tocEntryPointer->length == 0) {
912 // if we have a toc entry length of zero,
913 // then we've either reached the end of the sector, or the end of the dir
914 // so point to next sector (if there is one - will be checked by next condition)
915
916 tocEntryPointer = (struct DirTocEntry *)(cacheInfoDir.cache + (((((u8 *)tocEntryPointer - cacheInfoDir.cache) / 2048) + 1) * 2048));
917 }
918
919 if (tocEntryPointer >= (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048))) {
920 // we've reached the end of the current cache block (which may be end of entire dir
921 // so just break the loop
922 break;
923 }
924
925 // Check if the current entry is a dir or a file
926 if (tocEntryPointer->fileProperties & 0x02) {
927 DPRINTF("We found a dir, and we want all dirs\n\n");
928 copyToTocEntry(&localTocEntry, tocEntryPointer);
929
930 if (dir_entry == 0) {
931 if (cacheInfoDir.path_depth != 0) {
932 DPRINTF("It's the first directory entry, so name it '..'\n\n");
933 strcpy(localTocEntry.filename, "..");
934 }
935 }
936
937 // Copy from localTocEntry
938 tocEntry[matched_entries] = localTocEntry;
939 matched_entries++;
940 } else { // it must be a file
941 DPRINTF("We found a file, but we dont want files (at least not yet)\n\n");
942 }
943
944 dir_entry++;
945
946 if ((unsigned int)matched_entries >= req_entries) // if we've filled the requested buffer
947 return (matched_entries); // then just return
948
949 } // end of the current cache block
950
951 // if there is more dir to load, then load next chunk, else finish
952 if ((cacheInfoDir.cache_offset + cacheInfoDir.cache_size) < cacheInfoDir.sector_num) {
953 if (!cdfs_cacheDir(cacheInfoDir.pathname, CACHE_NEXT)) {
954 // failed to cache next block (should return TRUE even if
955 // there is no more directory, as long as a CD read didnt fail
956 return -1;
957 }
958 } else
959 break;
960
961 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
962 }
963
964 // Next do files
965 // Cache the start of the requested directory
966 if (!cdfs_cacheDir(cacheInfoDir.pathname, CACHE_START)) {
967 DPRINTF("cdfs_getDir - Call of cdfs_cacheDir failed\n\n");
968 return -1;
969 }
970
971 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
972
973 // skip the first self-referencing entry
974 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
975
976 // skip the parent entry if this is the root
977 if (cacheInfoDir.path_depth == 0)
978 tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
979
980 dir_entry = 0;
981
982 while (1) {
983 DPRINTF("cdfs_getDir - inside while-loop\n\n");
984
985 // parse the current cache block
986 for (; tocEntryPointer < (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048)); tocEntryPointer = (struct DirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
987 if (tocEntryPointer->length == 0) {
988 // if we have a toc entry length of zero,
989 // then we've either reached the end of the sector, or the end of the dir
990 // so point to next sector (if there is one - will be checked by next condition)
991
992 tocEntryPointer = (struct DirTocEntry *)(cacheInfoDir.cache + (((((u8 *)tocEntryPointer - cacheInfoDir.cache) / 2048) + 1) * 2048));
993 }
994
995 if (tocEntryPointer >= (struct DirTocEntry *)(cacheInfoDir.cache + (cacheInfoDir.cache_size * 2048))) {
996 // we've reached the end of the current cache block (which may be end of entire dir
997 // so just break the loop
998 break;
999 }
1000
1001 // Check if the current entry is a dir or a file
1002 if (tocEntryPointer->fileProperties & 0x02) {
1003 DPRINTF("We don't want files now\n\n");
1004 } else { // it must be a file
1005 copyToTocEntry(&localTocEntry, tocEntryPointer);
1006 // Copy from localTocEntry
1007 tocEntry[matched_entries] = localTocEntry;
1008 matched_entries++;
1009 }
1010
1011 dir_entry++;
1012
1013 if ((unsigned int)matched_entries >= req_entries) // if we've filled the requested buffer
1014 return (matched_entries); // then just return
1015
1016 } // end of the current cache block
1017
1018
1019 // if there is more dir to load, then load next chunk, else finish
1020 if ((cacheInfoDir.cache_offset + cacheInfoDir.cache_size) < cacheInfoDir.sector_num) {
1021 if (!cdfs_cacheDir(cacheInfoDir.pathname, CACHE_NEXT)) {
1022 // failed to cache next block (should return TRUE even if
1023 // there is no more directory, as long as a CD read didnt fail
1024 return -1;
1025 }
1026 } else
1027 break;
1028
1029 tocEntryPointer = (struct DirTocEntry *)cacheInfoDir.cache;
1030 }
1031 // reached the end of the dir, before filling up the requested entries
1032
1033 return (matched_entries);
1034}
1035
1036// This function uses sceCdTrayReq to check if the disc in the disc drive has changed.
1037// Once sceCdTrayReq is called it will reset the flag inside CDVDMAN.
1038// Avoid using sceCdTrayReq with SCECdTrayCheck as argument in other code if possible.
1039
1040int cdfs_checkDiskChanged(enum Cdvd_Changed_Index index) {
1041 u32 res = 0;
1043 if (res) {
1044 cdvdChangedMagic += 1;
1045 }
1046 if (cdvdChangedMagic != cdvdChangedMagicLast[index]) {
1047 cdvdChangedMagicLast[index] = cdvdChangedMagic;
1048 return TRUE;
1049 }
1050 return FALSE;
1051}
int sceCdGetError(void)
Definition cdi.c:40
int sceCdInit(int mode)
Definition cdi.c:64
int sceCdDiskReady(int mode)
Definition cdi.c:30
int sceCdGetDiskType(void)
Definition cdi.c:35
int sceCdSync(int mode)
Definition cdi.c:109
@ SCECdSpinStm
@ SCECdTrayCheck
@ SCECdPSCDDA
@ SCECdPSCD
@ SCECdDVDV
@ SCECdPS2DVD
@ SCECdPS2CDDA
@ SCECdPS2CD
int sceCdRead(u32 lbn, u32 sectors, void *buffer, sceCdRMode *mode)
Definition cdi.c:98
int sceCdTrayReq(int param, u32 *traychk)
Definition cdi.c:162
@ SCECdINoD
Definition cdfs_iop.c:14
Definition cdfs_iop.h:13