Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / vmc / mcman / ps2mc_io.c
blob99207eab6a128c6eaa83d380c2835b0aed0d7aba
1 /*
2 Copyright 2009-2010, jimmikaelkael
3 Licenced under Academic Free License version 3.0
4 Review Open PS2 Loader README & LICENSE files for further details.
5 */
7 #include "mcman.h"
9 extern char SUPERBLOCK_MAGIC[];
10 extern char SUPERBLOCK_VERSION[];
12 extern int mcman_wr_port;
13 extern int mcman_wr_slot;
14 extern int mcman_wr_block;
15 extern int mcman_wr_flag3;
16 extern int mcman_curdircluster;
18 extern u32 DOT;
19 extern u32 DOTDOT;
21 extern int PS1CardFlag;
23 //--------------------------------------------------------------
24 int mcman_format2(int port, int slot)
26 register int r, i, size, ifc_index, indirect_offset, allocatable_clusters_per_card;
27 register int ifc_length, fat_length, fat_entry, alloc_offset;
28 register int j = 0, z = 0;
29 MCDevInfo *mcdi = &mcman_devinfos[port][slot];
30 McCacheEntry *mce;
32 #ifdef DEBUG
33 DPRINTF("mcman: mcman_format2 port%d, slot%d cardform %d\n", port, slot, mcdi->cardform);
34 #endif
36 if (mcdi->cardform == sceMcResNoFormat) {
37 for (i = 0; i < 32; i++)
38 mcdi->bad_block_list[i] = -1;
39 mcdi->rootdir_cluster = 0;
40 mcdi->rootdir_cluster2 = 0;
41 goto lbl1;
44 if (mcdi->cardform > 0) {
45 if (((mcdi->version[0] - 48) >= 2) || ((mcdi->version[2] - 48) >= 2))
46 goto lbl1;
49 r = mcman_reportBadBlocks(port, slot);
50 if ((r != sceMcResSucceed) && (r != sceMcResNoFormat))
51 return sceMcResChangedCard;
53 lbl1:
54 // set superblock magic & version
55 memset((void *)&mcdi->magic, 0, sizeof (mcdi->magic) + sizeof (mcdi->version));
56 *((u32 *)&mcdi->magic ) = *((u32 *)&SUPERBLOCK_MAGIC );
57 *((u32 *)&mcdi->magic + 1) = *((u32 *)&SUPERBLOCK_MAGIC + 1);
58 *((u32 *)&mcdi->magic + 2) = *((u32 *)&SUPERBLOCK_MAGIC + 2);
59 *((u32 *)&mcdi->magic + 3) = *((u32 *)&SUPERBLOCK_MAGIC + 3);
60 *((u32 *)&mcdi->magic + 4) = *((u32 *)&SUPERBLOCK_MAGIC + 4);
61 *((u32 *)&mcdi->magic + 5) = *((u32 *)&SUPERBLOCK_MAGIC + 5);
62 *((u32 *)&mcdi->magic + 6) = *((u32 *)&SUPERBLOCK_MAGIC + 6);
63 *((u8 *)&mcdi->magic + 28) = *((u8 *)&SUPERBLOCK_MAGIC + 28);
65 strcat((char *)&mcdi->magic, SUPERBLOCK_VERSION);
67 //size = 8192 / mcdi->cluster_size; // get blocksize in cluster a better way must be found
68 size = mcdi->blocksize;
69 mcdi->cardform = -1;
71 mcman_wr_port = -1;
72 mcman_wr_slot = -1;
73 mcman_wr_block = -1;
74 mcman_wr_flag3 = -10;
76 //if (size <= 0)
77 // size = 1;
78 if (mcdi->blocksize <= 0)
79 size = 8;
81 // clear first 8 clusters
82 for (i = 0; i < size; i++) {
83 r = mcman_writecluster(port, slot, i, 1);
84 if (r == 0)
85 return sceMcResNoFormat;
87 if (r != 1)
88 return -40;
91 fat_length = (((mcdi->clusters_per_card << 2) - 1) / mcdi->cluster_size) + 1; // get length of fat in clusters
92 ifc_length = (((fat_length << 2) - 1) / mcdi->cluster_size) + 1; // get number of needed ifc clusters
94 if (!(ifc_length <= 32)) {
95 ifc_length = 32;
96 fat_length = mcdi->FATentries_per_cluster << 5;
99 // clear ifc clusters
100 if (ifc_length > 0) {
101 j = 0;
102 do {
103 if (i >= mcdi->clusters_per_card)
104 return sceMcResNoFormat;
106 do {
107 if (mcman_writecluster(port, slot, i, 1) != 0)
108 break;
110 i++;
111 } while (i < mcdi->clusters_per_card);
113 if (i >= mcdi->clusters_per_card)
114 return sceMcResNoFormat;
116 mcdi->ifc_list[j] = i;
117 j++;
118 i++;
119 } while (j < ifc_length);
122 // read ifc clusters to mc cache and clear fat clusters
123 if (fat_length > 0) {
124 j = 0;
126 do {
127 ifc_index = j / mcdi->FATentries_per_cluster;
128 indirect_offset = j % mcdi->FATentries_per_cluster;
130 if (indirect_offset == 0) {
131 if (mcman_readcluster(port, slot, mcdi->ifc_list[ifc_index], &mce) != sceMcResSucceed)
132 return -42;
133 mce->wr_flag = 1;
136 if (i >= mcdi->clusters_per_card)
137 return sceMcResNoFormat;
139 do {
140 r = mcman_writecluster(port, slot, i, 1);
141 if (r == 1)
142 break;
144 if (r < 0)
145 return -43;
147 i++;
148 } while (i < mcdi->clusters_per_card);
150 if (i >= mcdi->clusters_per_card)
151 return sceMcResNoFormat;
153 j++;
154 McFatCluster *fc = (McFatCluster *)mce->cl_data;
155 fc->entry[indirect_offset] = i;
156 i++;
158 } while (j < fat_length);
160 alloc_offset = i;
162 mcdi->backup_block1 = 0;
163 mcdi->backup_block2 = 0;
165 // clear backup blocks
166 for (i = (mcdi->clusters_per_card / mcdi->clusters_per_block) - 1; i > 0; i--) {
168 r = mcman_writecluster(port, slot, mcdi->clusters_per_block * i, 1);
169 if (r < 0)
170 return -44;
172 if ((r != 0) && (mcdi->backup_block1 == 0))
173 mcdi->backup_block1 = i;
174 else if ((r != 0) && (mcdi->backup_block2 == 0)) {
175 mcdi->backup_block2 = i;
176 break;
180 // set backup block2 to erased state
181 if (mcman_eraseblock(port, slot, mcdi->backup_block2, NULL, NULL) != sceMcResSucceed)
182 return -45;
184 u32 hi, lo, temp;
186 long_multiply(mcdi->clusters_per_card, 0x10624dd3, &hi, &lo);
187 temp = (hi >> 6) - (mcdi->clusters_per_card >> 31);
188 allocatable_clusters_per_card = (((((temp << 5) - temp) << 2) + temp) << 3) + 1;
189 j = alloc_offset;
191 // checking for bad allocated clusters and building FAT
192 if (j < i * mcdi->clusters_per_block) {
193 z = 0;
194 do { // quick check for bad clusters
195 r = mcman_writecluster(port, slot, j, 0);
196 if (r == 1) {
197 if (z == 0) {
198 mcdi->alloc_offset = j;
199 mcdi->rootdir_cluster = 0;
200 fat_entry = 0xffffffff; // marking rootdir end
202 else
203 fat_entry = 0x7fffffff; // marking free cluster
204 z++;
205 if (z == allocatable_clusters_per_card)
206 mcdi->max_allocatable_clusters = (j - mcdi->alloc_offset) + 1;
208 else {
209 if (r != 0)
210 return -45;
211 fat_entry = 0xfffffffd; // marking bad cluster
214 if (mcman_setFATentry(port, slot, j - mcdi->alloc_offset, fat_entry) != sceMcResSucceed)
215 return -46;
217 j++;
218 } while (j < (i * mcdi->clusters_per_block));
221 mcdi->alloc_end = (i * mcdi->clusters_per_block) - mcdi->alloc_offset;
223 if (mcdi->max_allocatable_clusters == 0)
224 mcdi->max_allocatable_clusters = i * mcdi->clusters_per_block;
226 if (z < mcdi->clusters_per_block)
227 return sceMcResNoFormat;
229 // read superblock to mc cache
230 for (i = 0; i < sizeof (MCDevInfo); i += MCMAN_CLUSTERSIZE) {
231 if (i < 0)
232 size = i + (MCMAN_CLUSTERSIZE - 1);
233 else
234 size = i;
236 if (mcman_readcluster(port, slot, size >> 10, &mce) != sceMcResSucceed)
237 return -48;
239 size = MCMAN_CLUSTERSIZE;
240 mce->wr_flag = 1;
242 if ((sizeof (MCDevInfo) - i) <= 1024)
243 size = sizeof (MCDevInfo) - i;
245 memcpy((void *)mce->cl_data, (void *)(mcdi + i), size);
248 mcdi->unknown1 = 0;
249 mcdi->unknown2 = 0;
250 mcdi->unknown5 = -1;
251 mcdi->rootdir_cluster2 = mcdi->rootdir_cluster;
253 // Create root dir
254 if (mcman_createDirentry(port, slot, 0, 0, 0, NULL) != sceMcResSucceed)
255 return -49;
257 // finally flush cache to memcard
258 r = mcman_flushmccache(port, slot);
259 if (r != sceMcResSucceed)
260 return r;
262 mcdi->cardform = 1;
264 return sceMcResSucceed;
267 //--------------------------------------------------------------
268 int mcman_dread2(int fd, fio_dirent_t *dirent)
270 register int r;
271 register MC_FHANDLE *fh = (MC_FHANDLE *)&mcman_fdhandles[fd];
272 McFsEntry *fse;
274 #ifdef DEBUG
275 DPRINTF("mcman: mcman_dread2 fd %d\n", fd);
276 #endif
278 if (fh->position >= fh->filesize)
279 return sceMcResSucceed;
281 do {
282 r = mcman_readdirentry(fh->port, fh->slot, fh->freeclink, fh->position, &fse);
283 if (r != sceMcResSucceed)
284 return r;
286 if (fse->mode & sceMcFileAttrExists)
287 break;
289 fh->position++;
290 } while (fh->position < fh->filesize);
292 if (fh->position >= fh->filesize)
293 return sceMcResSucceed;
295 fh->position++;
296 mcman_wmemset((void *)dirent, sizeof (fio_dirent_t), 0);
297 strcpy(dirent->name, fse->name);
298 *(u8 *)&dirent->name[32] = 0;
300 if (fse->mode & sceMcFileAttrReadable)
301 dirent->stat.mode |= sceMcFileAttrReadable;
302 if (fse->mode & sceMcFileAttrWriteable)
303 dirent->stat.mode |= sceMcFileAttrWriteable;
304 if (fse->mode & sceMcFileAttrExecutable)
305 dirent->stat.mode |= sceMcFileAttrExecutable;
306 if (fse->mode & sceMcFileAttrPS1)
307 dirent->stat.mode |= sceMcFileAttrPS1;
308 if (fse->mode & sceMcFileAttrPDAExec)
309 dirent->stat.mode |= sceMcFileAttrPDAExec;
310 if (fse->mode & sceMcFileAttrDupProhibit)
311 dirent->stat.mode |= sceMcFileAttrDupProhibit;
312 if (fse->mode & sceMcFileAttrSubdir)
313 dirent->stat.mode |= sceMcFileAttrSubdir;
314 else
315 dirent->stat.mode |= sceMcFileAttrFile;
317 dirent->stat.attr = fse->attr;
318 dirent->stat.size = fse->length;
319 *((u32 *)&dirent->stat.ctime ) = *((u32 *)&fse->created );
320 *((u32 *)&dirent->stat.ctime+1) = *((u32 *)&fse->created+1);
321 *((u32 *)&dirent->stat.mtime ) = *((u32 *)&fse->modified );
322 *((u32 *)&dirent->stat.mtime+1) = *((u32 *)&fse->modified+1);
324 return 1;
327 //--------------------------------------------------------------
328 int mcman_getstat2(int port, int slot, char *filename, fio_stat_t *stat)
330 register int r;
331 McFsEntry *fse;
333 #ifdef DEBUG
334 DPRINTF("mcman: mcman_getstat2 port%d slot%d filename %s\n", port, slot, filename);
335 #endif
337 r = mcman_cachedirentry(port, slot, filename, NULL, &fse, 1);
338 if (r != sceMcResSucceed)
339 return r;
341 mcman_wmemset((void *)stat, sizeof (fio_stat_t), 0);
343 if (fse->mode & sceMcFileAttrReadable)
344 stat->mode |= sceMcFileAttrReadable;
345 if (fse->mode & sceMcFileAttrWriteable)
346 stat->mode |= sceMcFileAttrWriteable;
347 if (fse->mode & sceMcFileAttrExecutable)
348 stat->mode |= sceMcFileAttrExecutable;
349 if (fse->mode & sceMcFileAttrPS1)
350 stat->mode |= sceMcFileAttrPS1;
351 if (fse->mode & sceMcFileAttrPDAExec)
352 stat->mode |= sceMcFileAttrPDAExec;
353 if (fse->mode & sceMcFileAttrDupProhibit)
354 stat->mode |= sceMcFileAttrDupProhibit;
355 if (fse->mode & sceMcFileAttrSubdir)
356 stat->mode |= sceMcFileAttrSubdir;
357 else
358 stat->mode |= sceMcFileAttrFile;
360 stat->attr = fse->attr;
362 if (!(fse->mode & sceMcFileAttrSubdir))
363 stat->size = fse->length;
365 *((u32 *)&stat->ctime ) = *((u32 *)&fse->created );
366 *((u32 *)&stat->ctime+1) = *((u32 *)&fse->created+1);
367 *((u32 *)&stat->mtime ) = *((u32 *)&fse->modified );
368 *((u32 *)&stat->mtime+1) = *((u32 *)&fse->modified+1);
370 return sceMcResSucceed;
373 //--------------------------------------------------------------
374 int mcman_setinfo2(int port, int slot, char *filename, sceMcTblGetDir *info, int flags)
376 register int r, fmode;
377 McFsEntry *fse;
378 McCacheDir dirInfo;
379 McFsEntry mfe;
380 u8 *pfsentry, *pfseend, *mfee;
382 #ifdef DEBUG
383 DPRINTF("mcman: mcman_setinfo2 port%d slot%d filename %s flags %x\n", port, slot, filename, flags);
384 #endif
386 r = mcman_cachedirentry(port, slot, filename, &dirInfo, &fse, 1); //dirInfo=sp218 fse=sp228
387 if (r != sceMcResSucceed)
388 return r;
390 if ((flags & sceMcFileAttrFile) != 0) {
391 if ((!strcmp(".", info->EntryName)) || (!strcmp("..", info->EntryName)))
392 return sceMcResNoEntry;
394 if (info->EntryName[0] == 0)
395 return sceMcResNoEntry;
397 r = mcman_chrpos(info->EntryName, '/');
398 if (r >= 0)
399 return sceMcResNoEntry;
401 if (dirInfo.fsindex < 2)
402 return sceMcResNoEntry;
404 r = mcman_readdirentry(port, slot, dirInfo.cluster, 0, &fse);
405 if (r != sceMcResSucceed)
406 return r;
408 r = mcman_readdirentry(port, slot, fse->cluster, fse->dir_entry, &fse);
409 if (r != sceMcResSucceed)
410 return r;
412 pfsentry = (u8 *)fse;
413 mfee = (u8 *)&mfe;
414 pfseend = (u8 *)(pfsentry + sizeof (McFsEntry));
416 do {
417 *((u32 *)mfee ) = *((u32 *)pfsentry );
418 *((u32 *)mfee+1) = *((u32 *)pfsentry+1);
419 *((u32 *)mfee+2) = *((u32 *)pfsentry+2);
420 *((u32 *)mfee+3) = *((u32 *)pfsentry+3);
421 pfsentry += 16;
422 mfee += 16;
423 } while (pfsentry < pfseend);
425 r = mcman_getdirinfo(port, slot, &mfe, info->EntryName, NULL, 1);
426 if (r != 1) {
427 if (r < 2) {
428 if (r == 0)
429 return sceMcResNoEntry;
430 return r;
432 else {
433 if (r != 2)
434 return r;
435 return sceMcResDeniedPermit;
440 r = mcman_readdirentry(port, slot, dirInfo.cluster, dirInfo.fsindex, &fse);
441 if (r != sceMcResSucceed)
442 return r;
444 mcman_1stcacheEntsetwrflagoff();
446 //Special fix clause for file managers (like uLaunchELF)
447 //This allows writing most entries that can be read by mcGetDir
448 //and without usual restrictions. This flags value should cause no conflict
449 //as Sony code never uses it, and the value is changed after its use here.
450 if(flags == 0xFEED){
451 fse->mode = info->AttrFile;
452 //fse->unused = info->Reserve1;
453 //fse->length = info->FileSizeByte;
454 flags = sceMcFileAttrReadable|sceMcFileAttrWriteable;
455 //The changed flags value allows more entries to be copied below
458 if ((flags & sceMcFileAttrDupProhibit) != 0)
459 fse->attr = info->Reserve2;
461 if ((flags & sceMcFileAttrExecutable) != 0) {
462 fmode = 0xffff7fcf;
463 if (!PS1CardFlag)
464 fmode = 0x180f;
465 fse->mode = (fse->mode & ~fmode) | (info->AttrFile & fmode);
468 if ((flags & sceMcFileCreateFile) != 0) {
469 fmode = 0x380f;
470 if (!PS1CardFlag)
471 fmode = 0x180f;
472 fse->mode = (fse->mode & ~fmode) | (info->AttrFile & fmode);
475 if ((flags & sceMcFileAttrReadable) != 0)
476 fse->created = info->_Create;
478 if ((flags & sceMcFileAttrWriteable) != 0)
479 fse->modified = info->_Modify;
481 if ((flags & sceMcFileAttrFile) != 0) {
482 strncpy(fse->name, info->EntryName, 32);
483 fse->name[31] = 0;
486 return sceMcResSucceed;
489 //--------------------------------------------------------------
490 int mcman_read2(int fd, void *buffer, int nbyte)
492 register int r, temp, rpos, size, offset;
493 register MC_FHANDLE *fh = (MC_FHANDLE *)&mcman_fdhandles[fd];
494 register MCDevInfo *mcdi = &mcman_devinfos[fh->port][fh->slot];
495 McCacheEntry *mce;
497 #ifdef DEBUG
498 DPRINTF("mcman: mcman_read2 fd %d buf %x size %d\n", fd, (int)buffer, nbyte);
499 #endif
501 if (fh->position < fh->filesize) {
503 temp = fh->filesize - fh->position;
504 if (nbyte > temp)
505 nbyte = temp;
507 rpos = 0;
508 if (nbyte > 0) {
510 do {
511 offset = fh->position % mcdi->cluster_size; // file pointer offset % cluster size
512 temp = mcdi->cluster_size - offset;
513 if (temp < nbyte)
514 size = temp;
515 else
516 size = nbyte;
518 r = mcman_fatRseek(fd);
520 if (r <= 0)
521 return r;
523 r = mcman_readcluster(fh->port, fh->slot, r, &mce);
524 if (r != sceMcResSucceed)
525 return r;
527 memcpy((void *)(buffer + rpos), (void *)(mce->cl_data + offset), size);
529 rpos += size;
530 mce->rd_flag = 1;
531 nbyte -= size;
532 fh->position += size;
534 } while (nbyte);
536 return rpos;
539 return 0;
542 //--------------------------------------------------------------
543 int mcman_write2(int fd, void *buffer, int nbyte)
545 register int r, r2, wpos, size, offset;
546 register MC_FHANDLE *fh = (MC_FHANDLE *)&mcman_fdhandles[fd];
547 register MCDevInfo *mcdi = &mcman_devinfos[fh->port][fh->slot];
548 McCacheEntry *mce;
550 if (nbyte) {
551 if (fh->unknown2 == 0) {
552 fh->unknown2 = 1;
553 r = mcman_close2(fd);
554 if (r != sceMcResSucceed)
555 return r;
556 r = mcman_flushmccache(fh->port, fh->slot);
557 if (r != sceMcResSucceed)
558 return r;
562 wpos = 0;
563 if (nbyte) {
564 do {
565 r = mcman_fatRseek(fd);
566 if (r == sceMcResFullDevice) {
568 r2 = mcman_fatWseek(fd);
569 if (r2 == r)
570 return sceMcResFullDevice;
572 if (r2 != sceMcResSucceed)
573 return r2;
575 r = mcman_fatRseek(fd);
577 else {
578 if (r < 0)
579 return r;
582 r = mcman_readcluster(fh->port, fh->slot, r, &mce);
583 if (r != sceMcResSucceed)
584 return r;
586 mce->rd_flag = 1;
588 offset = fh->position % mcdi->cluster_size; // file pointer offset % cluster size
589 r2 = mcdi->cluster_size - offset;
590 if (r2 < nbyte)
591 size = r2;
592 else
593 size = nbyte;
595 memcpy((void *)(mce->cl_data + offset), (void *)(buffer + wpos), size);
597 mce->wr_flag = 1;
599 r = fh->position + size;
600 fh->position += size;
602 if (r < fh->filesize)
603 r = fh->filesize ;
605 fh->filesize = r;
607 nbyte -= size;
608 wpos += size;
610 } while (nbyte);
613 r = mcman_close2(fd);
614 if (r != sceMcResSucceed)
615 return r;
617 return wpos;
620 //--------------------------------------------------------------
621 int mcman_close2(int fd)
623 register int r, fmode;
624 register MC_FHANDLE *fh = (MC_FHANDLE *)&mcman_fdhandles[fd];
625 McFsEntry *fse1, *fse2;
627 #ifdef DEBUG
628 DPRINTF("mcman: mcman_close2 fd %d\n", fd);
629 #endif
631 r = mcman_readdirentry(fh->port, fh->slot, fh->field_20, fh->field_24, &fse1);
632 if (r != sceMcResSucceed)
633 return -31;
635 if (fh->unknown2 == 0) {
636 fmode = fse1->mode | sceMcFileAttrClosed;
638 else {
639 fmode = fse1->mode & 0xff7f;
641 fse1->mode = fmode;
643 mcman_getmcrtime(&fse1->modified);
645 fse1->cluster = fh->freeclink;
646 fse1->length = fh->filesize;
648 mcman_1stcacheEntsetwrflagoff();
650 mcman_fsmodtime = fse1->modified;
652 r = mcman_readdirentry(fh->port, fh->slot, fh->field_28, fh->field_2C, &fse2);
653 if (r != sceMcResSucceed)
654 return r;
656 fse2->modified = mcman_fsmodtime;
658 mcman_1stcacheEntsetwrflagoff();
660 return sceMcResSucceed;
663 //--------------------------------------------------------------
664 int mcman_open2(int port, int slot, char *filename, int flags)
666 register int fd, i, r, fsindex, fsoffset, fat_index, rdflag, wrflag, pos, mcfree;
667 register MC_FHANDLE *fh, *fh2;
668 register MCDevInfo *mcdi;
669 McCacheDir cacheDir;
670 McFsEntry *fse1, *fse2;
671 McCacheEntry *mce;
672 u8 *p, *pfsentry, *pcache, *pfseend;
673 int fat_entry;
675 #ifdef DEBUG
676 DPRINTF("mcman: mcman_open2 port%d slot%d name %s flags %x\n", port, slot, filename, flags);
677 #endif
679 if ((flags & sceMcFileCreateFile) != 0)
680 flags |= sceMcFileAttrWriteable; // s5
682 //if (!mcman_checkpath(filename))
683 // return sceMcResNoEntry;
684 if (filename[0] == 0)
685 return sceMcResNoEntry;
687 fd = 0;
688 do {
689 fh = (MC_FHANDLE *)&mcman_fdhandles[fd];
690 if (fh->status == 0)
691 break;
692 } while (++fd < MAX_FDHANDLES);
694 if (fd == MAX_FDHANDLES)
695 return sceMcResUpLimitHandle;
697 fh = (MC_FHANDLE *)&mcman_fdhandles[fd]; // s2
699 mcman_wmemset((void *)fh, sizeof (MC_FHANDLE), 0);
701 mcdi = (MCDevInfo *)&mcman_devinfos[port][slot]; // s3
703 if ((flags & (sceMcFileCreateFile | sceMcFileCreateDir)) == 0)
704 cacheDir.maxent = -1; //sp20
705 else
706 cacheDir.maxent = 0; //sp20
708 //fse1 = sp28
709 //sp18 = cacheDir
711 fse1 = NULL;
712 r = mcman_cachedirentry(port, slot, filename, &cacheDir, &fse1, 1);
713 if (r < 0)
714 return r;
716 if (fse1) {
717 pfsentry = (u8 *)fse1;
718 pcache = (u8 *)&mcman_dircache[1];
719 pfseend = (u8 *)(pfsentry + sizeof(McFsEntry));
721 do {
722 *((u32 *)pcache ) = *((u32 *)pfsentry );
723 *((u32 *)pcache+1) = *((u32 *)pfsentry+1);
724 *((u32 *)pcache+2) = *((u32 *)pfsentry+2);
725 *((u32 *)pcache+3) = *((u32 *)pfsentry+3);
726 pfsentry += 16;
727 pcache += 16;
728 } while (pfsentry < pfseend);
731 if ((flags == 0) && ((fse1->mode & sceMcFileAttrExists) == 0))
732 r = 1;
734 if (r == 2)
735 return sceMcResNoEntry;
737 if (r == 3)
738 return sceMcResDeniedPermit;
740 if ((r == 0) && ((flags & sceMcFileCreateDir) != 0))
741 return sceMcResNoEntry;
743 if ((r == 1) && ((flags & (sceMcFileCreateFile | sceMcFileCreateDir)) == 0))
744 return sceMcResNoEntry;
746 rdflag = flags & sceMcFileAttrReadable;
747 wrflag = flags & sceMcFileAttrWriteable;
748 fh->freeclink = -1;
749 fh->clink = -1;
750 fh->clust_offset = 0;
751 fh->filesize = 0;
752 fh->position = 0;
753 fh->port = port;
754 fh->slot = slot;
755 fh->unknown2 = 0;
756 fh->rdflag = rdflag;
757 fh->wrflag = wrflag;
758 fh->unknown1 = 0;
759 fh->field_20 = cacheDir.cluster;
760 fh->field_24 = cacheDir.fsindex;
762 // fse2 = sp2c
764 if (r == 0) {
766 if ((wrflag != 0) && ((mcman_dircache[1].mode & sceMcFileAttrWriteable) == 0))
767 return sceMcResDeniedPermit;
769 if (!PS1CardFlag) {
770 if ((flags & sceMcFileAttrReadable) != 0) {
771 if ((mcman_dircache[1].mode & sceMcFileAttrReadable) == 0)
772 return sceMcResDeniedPermit;
775 r = mcman_readdirentry(port, slot, cacheDir.cluster, 0, &fse2);
776 if (r != sceMcResSucceed)
777 return r;
779 fh->field_28 = fse2->cluster;
780 fh->field_2C = fse2->dir_entry;
782 if ((mcman_dircache[1].mode & sceMcFileAttrSubdir) != 0) {
783 if ((mcman_dircache[1].mode & sceMcFileAttrReadable) == 0)
784 return sceMcResDeniedPermit;
786 fh->freeclink = mcman_dircache[1].cluster;
787 fh->rdflag = 0;
788 fh->wrflag = 0;
789 fh->unknown1 = 0;
790 fh->drdflag = 1;
791 fh->status = 1;
792 fh->filesize = mcman_dircache[1].length;
793 fh->clink = fh->freeclink;
795 return fd;
798 if ((flags & sceMcFileAttrWriteable) != 0) {
799 i = 0;
800 do {
801 fh2 = (MC_FHANDLE *)&mcman_fdhandles[i];
803 if ((fh2->status == 0) || (fh2->port != port) || (fh2->slot != slot) \
804 || (fh2->field_20 != cacheDir.cluster) || (fh2->field_24 != cacheDir.fsindex))
805 continue;
807 if (fh2->wrflag != 0)
808 return sceMcResDeniedPermit;
810 } while (++i < MAX_FDHANDLES);
813 if ((flags & sceMcFileCreateFile) != 0) {
814 r = mcman_setdirentrystate(port, slot, cacheDir.cluster, cacheDir.fsindex, 0);
815 mcman_flushmccache(port, slot);
817 if (r != sceMcResSucceed)
818 return -43;
820 if (cacheDir.fsindex < cacheDir.maxent)
821 cacheDir.maxent = cacheDir.fsindex;
823 else {
824 fh->freeclink = mcman_dircache[1].cluster;
825 fh->filesize = mcman_dircache[1].length;
826 fh->clink = fh->freeclink;
828 if (fh->rdflag != 0)
829 fh->rdflag = (*((u8 *)&mcman_dircache[1].mode)) & sceMcFileAttrReadable;
830 else
831 fh->rdflag = 0;
833 if (fh->wrflag != 0)
834 fh->wrflag = (mcman_dircache[1].mode >> 1) & sceMcFileAttrReadable;
835 else
836 fh->wrflag = 0;
838 fh->status = 1;
840 return fd;
843 else {
844 fh->field_28 = cacheDir.cluster;
845 fh->field_2C = cacheDir.fsindex;
848 r = mcman_readdirentry(port, slot, fh->field_28, fh->field_2C, &fse1);
849 if (r != sceMcResSucceed)
850 return r;
852 pfsentry = (u8 *)fse1;
853 pcache = (u8 *)&mcman_dircache[2];
854 pfseend = (u8 *)(pfsentry + sizeof(McFsEntry));
856 do {
857 *((u32 *)pcache ) = *((u32 *)pfsentry );
858 *((u32 *)pcache+1) = *((u32 *)pfsentry+1);
859 *((u32 *)pcache+2) = *((u32 *)pfsentry+2);
860 *((u32 *)pcache+3) = *((u32 *)pfsentry+3);
861 pfsentry += 16;
862 pcache += 16;
863 } while (pfsentry < pfseend);
865 i = -1;
866 if (mcman_dircache[2].length == cacheDir.maxent) {
868 fsindex = mcman_dircache[2].length / (mcdi->cluster_size >> 9); //v1
869 fsoffset = mcman_dircache[2].length % (mcdi->cluster_size >> 9); //v0
871 if (fsoffset == 0) {
872 fat_index = mcman_dircache[2].cluster;
873 i = fsindex;
875 if ((mcman_dircache[2].cluster == 0) && (i >= 2)) {
876 if (mcman_getFATindex(port, slot, i - 1) >= 0) {
877 fat_index = mcman_getFATindex(port, slot, i - 1); // s3
878 i = 1;
881 i--;
883 if (i != -1) {
885 do {
886 r = mcman_getFATentry(port, slot, fat_index, &fat_entry);
887 if (r != sceMcResSucceed)
888 return r;
890 if (fat_entry >= -1) {
891 r = mcman_findfree2(port, slot, 1);
892 if (r < 0)
893 return r;
895 fat_entry = r;
896 mce = mcman_get1stcacheEntp(); // s4
898 fat_entry |= 0x80000000;
900 r = mcman_setFATentry(port, slot, fat_index, fat_entry);
901 if (r != sceMcResSucceed)
902 return r;
904 mcman_addcacheentry(mce);
906 i--;
907 fat_index = fat_entry & 0x7fffffff;
909 } while (i != -1);
913 r = mcman_flushmccache(port, slot);
914 if (r != sceMcResSucceed)
915 return r;
917 i = -1;
919 mcman_dircache[2].length++;
922 do {
923 p = (u8 *)(filename + i + 1);
924 pos = i + 1;
925 r = mcman_chrpos(p, '/');
926 if (r < 0)
927 break;
928 i = pos + r;
929 } while (1);
931 p = (char *)(filename + pos);
933 mcfree = 0;
935 if ((flags & sceMcFileCreateDir) != 0) {
936 r = mcman_findfree2(port, slot, 1); // r = s3
937 if (r < 0)
938 return r;
939 mcfree = r;
942 mce = mcman_get1stcacheEntp(); // mce = s4
944 mcman_getmcrtime(&mcman_dircache[2].modified);
946 r = mcman_readdirentry(port, slot, mcman_dircache[2].cluster, cacheDir.maxent, &fse2);
947 if (r != sceMcResSucceed)
948 return r;
950 mcman_wmemset((void *)fse2, sizeof (McFsEntry), 0);
952 strncpy((void *)fse2->name, p, 32);
954 fse2->created = mcman_dircache[2].modified;
955 fse2->modified = mcman_dircache[2].modified;
957 mcman_1stcacheEntsetwrflagoff();
959 mcman_addcacheentry(mce);
961 if (!PS1CardFlag)
962 flags &= 0xffffdfff;
964 if ((flags & sceMcFileCreateDir) != 0) {
966 fse2->mode = ((flags & sceMcFileAttrHidden) | sceMcFileAttrReadable | sceMcFileAttrWriteable \
967 | sceMcFileAttrExecutable | sceMcFileAttrSubdir | sceMcFile0400 | sceMcFileAttrExists) // 0x8427
968 | (flags & (sceMcFileAttrPS1 | sceMcFileAttrPDAExec));
969 fse2->length = 2;
970 fse2->cluster = mcfree;
972 r = mcman_createDirentry(port, slot, mcman_dircache[2].cluster, cacheDir.maxent, mcfree, (sceMcStDateTime *)&fse2->created);
973 if (r != sceMcResSucceed)
974 return -46;
976 r = mcman_readdirentry(port, slot, fh->field_28, fh->field_2C, &fse1);
977 if (r != sceMcResSucceed)
978 return r;
980 pfsentry = (u8 *)fse1;
981 pcache = (u8 *)&mcman_dircache[2];
982 pfseend = (u8 *)(pfsentry + sizeof(McFsEntry));
984 do {
985 *((u32 *)pfsentry ) = *((u32 *)pcache );
986 *((u32 *)pfsentry+1) = *((u32 *)pcache+1);
987 *((u32 *)pfsentry+2) = *((u32 *)pcache+2);
988 *((u32 *)pfsentry+3) = *((u32 *)pcache+3);
989 pfsentry += 16;
990 pcache += 16;
991 } while (pfsentry < pfseend);
993 mcman_1stcacheEntsetwrflagoff();
995 r = mcman_flushmccache(port, slot);
996 if (r != sceMcResSucceed)
997 return r;
999 return sceMcResSucceed;
1001 else {
1002 fse2->mode = ((flags & sceMcFileAttrHidden) | sceMcFileAttrReadable | sceMcFileAttrWriteable \
1003 | sceMcFileAttrExecutable | sceMcFileAttrFile | sceMcFile0400 | sceMcFileAttrExists) // 0x8417
1004 | (flags & (sceMcFileAttrPS1 | sceMcFileAttrPDAExec));
1006 fse2->cluster = -1;
1007 fh->field_20 = mcman_dircache[2].cluster;
1008 fh->status = 1;
1009 fh->field_24 = cacheDir.maxent;
1011 r = mcman_readdirentry(port, slot, fh->field_28, fh->field_2C, &fse1);
1012 if (r != sceMcResSucceed)
1013 return r;
1015 pfsentry = (u8 *)fse1;
1016 pcache = (u8 *)&mcman_dircache[2];
1017 pfseend = (u8 *)(pfsentry + sizeof(McFsEntry));
1019 do {
1020 *((u32 *)pfsentry ) = *((u32 *)pcache );
1021 *((u32 *)pfsentry+1) = *((u32 *)pcache+1);
1022 *((u32 *)pfsentry+2) = *((u32 *)pcache+2);
1023 *((u32 *)pfsentry+3) = *((u32 *)pcache+3);
1024 pfsentry += 16;
1025 pcache += 16;
1026 } while (pfsentry < pfseend);
1028 mcman_1stcacheEntsetwrflagoff();
1030 r = mcman_flushmccache(port, slot);
1031 if (r != sceMcResSucceed)
1032 return r;
1035 return fd;
1038 //--------------------------------------------------------------
1039 int mcman_chdir(int port, int slot, char *newdir, char *currentdir)
1041 register int r, len, len2, cluster;
1042 register MCDevInfo *mcdi = &mcman_devinfos[port][slot];
1043 McCacheDir cacheDir;
1044 McFsEntry *fse;
1046 #ifdef DEBUG
1047 DPRINTF("mcman: mcman_chdir port%d slot%d newdir %s\n", port, slot, newdir);
1048 #endif
1050 //if (!mcman_checkpath(newdir))
1051 // return sceMcResNoEntry;
1053 cacheDir.maxent = -1;
1055 r = mcman_cachedirentry(port, slot, newdir, &cacheDir, &fse, 1);
1056 if (r < 0)
1057 return r;
1059 if (((u32)(r - 1)) < 2)
1060 return sceMcResNoEntry;
1062 mcdi->rootdir_cluster2 = cacheDir.cluster;
1063 mcdi->unknown1 = cacheDir.fsindex;
1065 cluster = cacheDir.cluster;
1066 if (!strcmp(fse->name, "..")) {
1067 r = mcman_readdirentry(port, slot, cluster, 0, &fse);
1068 if (r != sceMcResSucceed)
1069 return r;
1072 if (!strcmp(fse->name, ".")) {
1073 mcdi->rootdir_cluster2 = fse->cluster;
1074 mcdi->unknown1 = fse->dir_entry;
1076 cluster = fse->cluster;
1077 r = mcman_readdirentry(port, slot, cluster, fse->dir_entry, &fse);
1078 if (r != sceMcResSucceed)
1079 return r;
1082 currentdir[0] = 0;
1084 lbl1:
1085 if (strcmp(fse->name, ".")) {
1087 if (strlen(fse->name) < 32)
1088 len = strlen(fse->name);
1089 else
1090 len = 32;
1092 if (strlen(currentdir)) {
1093 len2 = strlen(currentdir);
1094 if (len2 >= 0) {
1095 do {
1096 currentdir[1 + len2 + len] = currentdir[len2];
1097 } while (--len2 >= 0);
1099 currentdir[len] = '/';
1100 strncpy(currentdir, fse->name, len);
1102 else {
1103 strncpy(currentdir, fse->name, 32);
1104 currentdir[32] = 0;
1107 r = mcman_readdirentry(port, slot, cluster, 0, &fse);
1108 if (r != sceMcResSucceed)
1109 return r;
1111 r = mcman_readdirentry(port, slot, fse->cluster, fse->dir_entry, &fse);
1113 if (r == sceMcResSucceed)
1114 goto lbl1;
1116 return r;
1118 else {
1119 strlen(fse->name);
1120 len = strlen(currentdir);
1122 if (len >= 0) {
1123 do {
1124 currentdir[1 + len] = currentdir[len];
1125 } while (--len >= 0);
1127 currentdir[0] = '/';
1129 r = sceMcResSucceed;
1132 return sceMcResSucceed;
1135 //--------------------------------------------------------------
1136 int mcman_getdir2(int port, int slot, char *dirname, int flags, int maxent, sceMcTblGetDir *info)
1138 register int r, pos, nument;
1139 register MCDevInfo *mcdi = &mcman_devinfos[port][slot];
1140 McFsEntry *fse;
1141 char *p;
1143 #ifdef DEBUG
1144 DPRINTF("mcman: mcman_getdir2 port%d slot%d dir=%s flags=%d maxent=%d\n", port, slot, dirname, flags, maxent);
1145 #endif
1147 nument = 0;
1148 flags &= 0xffff;
1150 if (!flags) {
1152 p = (char *)mcman_curdirpath;
1153 strncpy(p, dirname, 1023);
1154 mcman_curdirpath[1023] = 0;
1156 pos = -1; // s1
1157 p++; //s0
1158 do {
1159 r = mcman_chrpos((void *)&p[pos], '/');
1160 if (r < 0)
1161 break;
1162 pos += 1 + r;
1163 } while (1);
1165 if (pos <= 0) {
1166 if (pos == 0)
1167 *p = 0;
1168 else
1169 p[-1] = 0;
1171 else {
1172 mcman_curdirpath[pos] = 0;
1175 mcman_curdirname = &dirname[pos] + 1;
1177 r = mcman_cachedirentry(port, slot, mcman_curdirpath, NULL, &fse, 1);
1178 if (r > 0)
1179 return sceMcResNoEntry;
1180 if (r < 0)
1181 return r;
1183 if (!(fse->mode & sceMcFileAttrSubdir)) {
1184 mcman_curdircluster = -1;
1185 return sceMcResNoEntry;
1188 mcman_curdircluster = fse->cluster;
1189 mcman_curdirlength = fse->length;
1191 if ((fse->cluster == mcdi->rootdir_cluster) && (fse->dir_entry == 0))
1192 mcman_curdirmaxent = 2;
1193 else
1194 mcman_curdirmaxent = 0;
1196 else {
1197 if (mcman_curdircluster < 0)
1198 return sceMcResNoEntry;
1201 if (maxent != 0) {
1202 do {
1203 if (mcman_curdirmaxent >= mcman_curdirlength)
1204 break;
1206 r = mcman_readdirentry(port, slot, mcman_curdircluster, mcman_curdirmaxent, &fse);
1207 if (r != sceMcResSucceed)
1208 return r;
1210 mcman_curdirmaxent++;
1212 if (!(fse->mode & sceMcFileAttrExists))
1213 continue;
1214 if ((fse->mode & sceMcFileAttrHidden) && (!PS1CardFlag))
1215 continue;
1216 if (!mcman_checkdirpath(fse->name, mcman_curdirname))
1217 continue;
1219 mcman_wmemset((void *)info, sizeof (sceMcTblGetDir), 0);
1221 if (mcman_curdirmaxent == 2) {
1223 r = mcman_readdirentry(port, slot, mcman_curdircluster, 0, &fse);
1224 if (r != sceMcResSucceed)
1225 return r;
1227 r = mcman_readdirentry(port, slot, fse->cluster, 0, &fse);
1228 if (r != sceMcResSucceed)
1229 return r;
1231 r = mcman_readdirentry(port, slot, fse->cluster, fse->dir_entry, &fse);
1232 if (r != sceMcResSucceed)
1233 return r;
1235 *(u16 *)&info->EntryName = *(u16 *)&DOTDOT;
1236 *(u8 *)&info->EntryName[2] = *((u8 *)&DOTDOT+2);
1238 else if (mcman_curdirmaxent == 1) {
1240 r = mcman_readdirentry(port, slot, mcman_curdircluster, 0, &fse);
1241 if (r != sceMcResSucceed)
1242 return r;
1244 r = mcman_readdirentry(port, slot, fse->cluster, fse->dir_entry, &fse);
1245 if (r != sceMcResSucceed)
1246 return r;
1248 *(u16 *)&info->EntryName = *(u16 *)&DOT;
1250 else {
1251 strncpy(info->EntryName, fse->name, 32);
1254 info->AttrFile = fse->mode;
1255 info->Reserve1 = fse->unused;
1257 info->_Create = fse->created;
1258 info->_Modify = fse->modified;
1260 if (!(fse->mode & sceMcFileAttrSubdir))
1261 info->FileSizeByte = fse->length;
1263 nument++;
1264 maxent--;
1265 info++;
1267 } while (maxent);
1270 return nument;
1273 //--------------------------------------------------------------
1274 int mcman_delete2(int port, int slot, char *filename, int flags)
1276 register int r, i;
1277 McCacheDir cacheDir;
1278 McFsEntry *fse1, *fse2;
1280 #ifdef DEBUG
1281 DPRINTF("mcman: mcman_delete2 port%d slot%d filename %s flags %x\n", port, slot, filename, flags);
1282 #endif
1284 //if (!mcman_checkpath(filename))
1285 // return sceMcResNoEntry;
1287 r = mcman_cachedirentry(port, slot, filename, &cacheDir, &fse1, ((u32)(flags < 1)) ? 1 : 0);
1288 if (r > 0)
1289 return sceMcResNoEntry;
1290 if (r < 0)
1291 return r;
1293 if (!flags) {
1294 if (!(fse1->mode & sceMcFileAttrExists))
1295 return sceMcResNoEntry;
1297 else {
1298 if (fse1->mode & sceMcFileAttrExists)
1299 return sceMcResNoEntry;
1302 if ((!PS1CardFlag) && (!flags)) {
1303 if (!(fse1->mode & sceMcFileAttrWriteable))
1304 return sceMcResDeniedPermit;
1307 if ((!fse1->cluster) && (!fse1->dir_entry))
1308 return sceMcResNoEntry;
1310 i = 2;
1311 if ((!flags) && (fse1->mode & sceMcFileAttrSubdir) && (i < fse1->length)) {
1313 do {
1314 r = mcman_readdirentry(port, slot, fse1->cluster, i, &fse2);
1315 if (r != sceMcResSucceed)
1316 return r;
1318 if (fse2->mode & sceMcFileAttrExists)
1319 return sceMcResNotEmpty;
1321 } while (++i < fse1->length);
1324 r = mcman_setdirentrystate(port, slot, cacheDir.cluster, cacheDir.fsindex, flags);
1325 if (r != sceMcResSucceed)
1326 return r;
1328 r = mcman_flushmccache(port, slot);
1329 if (r != sceMcResSucceed)
1330 return r;
1332 return sceMcResSucceed;
1335 //--------------------------------------------------------------
1336 int mcman_unformat2(int port, int slot)
1338 register int r, i, j, z, l, pageword_cnt, page, blocks_on_card, erase_byte, err_cnt;
1339 register u32 erase_value;
1340 register MCDevInfo *mcdi = &mcman_devinfos[port][slot];
1342 #ifdef DEBUG
1343 DPRINTF("mcman: mcman_unformat2 port%d slot%d\n", port, slot);
1344 #endif
1346 pageword_cnt = mcdi->pagesize >> 2;
1347 blocks_on_card = mcdi->clusters_per_card / mcdi->clusters_per_block; //sp18
1349 erase_value = 0xffffffff; //s6
1350 if (!(mcdi->cardflags & CF_ERASE_ZEROES))
1351 erase_value = 0x00000000;
1353 for (i = 0; i < pageword_cnt; i++)
1354 *((u32 *)&mcman_pagebuf + i) = erase_value;
1356 for (i = 0; i < 128; i++)
1357 *((u32 *)&mcman_eccdata + i) = erase_value;
1359 i = 1;
1360 if (i < blocks_on_card) {
1361 erase_byte = erase_value & 0xff; // sp20
1362 do {
1363 page = i * mcdi->blocksize;
1364 if (mcdi->cardform > 0) {
1365 j = 0;
1366 for (j = 0; j < 16; j++) {
1367 if (mcdi->bad_block_list[j] <= 0) {
1368 j = 16;
1369 goto lbl1;
1371 if (mcdi->bad_block_list[j] == i)
1372 goto lbl1;
1375 else {
1376 err_cnt = 0;
1377 j = -1;
1378 z = 0;
1379 if (mcdi->blocksize > 0) {
1380 do {
1381 r = McReadPage(port, slot, page + z, mcman_pagebuf);
1382 if (r == sceMcResNoFormat) {
1383 j = -2;
1384 break;
1386 if (r != sceMcResSucceed)
1387 return -42;
1389 if ((mcdi->cardflags & CF_USE_ECC) == 0) {
1390 for (l = 0; l < mcdi->pagesize; l++) {
1391 if (mcman_pagebuf[l] != erase_byte)
1392 err_cnt++;
1393 if (err_cnt >= (mcdi->clusters_per_block << 6)) {
1394 j = 16;
1395 break;
1398 if (j != -1)
1399 break;
1401 } while (++z < mcdi->blocksize);
1405 if (((mcdi->cardflags & CF_USE_ECC) != 0) && (j == -1))
1406 j = 16;
1407 lbl1:
1408 if (j == 16) {
1409 r = mcman_eraseblock(port, slot, i, NULL, NULL);
1410 if (r != sceMcResSucceed)
1411 return -43;
1413 else {
1414 for (l = 0; l < pageword_cnt; l++)
1415 *((u32 *)&mcman_pagebuf + l) = erase_value;
1417 if (mcdi->blocksize > 0) {
1418 z = 0;
1419 do {
1420 r = McWritePage(port, slot, page + z, mcman_pagebuf, mcman_eccdata);
1421 if (r != sceMcResSucceed)
1422 return -44;
1423 } while (++z < mcdi->blocksize);
1426 } while (++i < blocks_on_card);
1429 r = mcman_eraseblock(port, slot, 0, NULL, NULL);
1430 if (r != sceMcResSucceed)
1431 return -45;
1433 return sceMcResSucceed;
1436 //--------------------------------------------------------------