PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
hdck.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include <atad.h>
12#include <errno.h>
13#include <iomanX.h>
14#include <loadcore.h>
15#include <stdio.h>
16#include <sysclib.h>
17#include <irx.h>
18#include <hdd-ioctl.h>
19
20#include "libapa.h"
21
22#include "misc_hdck.h"
23
24#ifdef _IOP
25IRX_ID("hdck", APA_MODVER_MAJOR, APA_MODVER_MINOR);
26#endif
27
28// Function prototypes
29static int HdckInit(iomanX_iop_device_t *device);
30static int HdckDevctl(iomanX_iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
31
32static u8 IOBuffer[128 * 512];
33static u8 IOBuffer2[128 * 512];
34
35IOMANX_RETURN_VALUE_IMPL(0);
36IOMANX_RETURN_VALUE_IMPL(EPERM);
37
38static iomanX_iop_device_ops_t HdckDeviceOps = {
39 &HdckInit, // init
40 IOMANX_RETURN_VALUE(0), // deinit
41 IOMANX_RETURN_VALUE(EPERM), // format
42 IOMANX_RETURN_VALUE(EPERM), // open
43 IOMANX_RETURN_VALUE(EPERM), // close
44 IOMANX_RETURN_VALUE(EPERM), // read
45 IOMANX_RETURN_VALUE(EPERM), // write
46 IOMANX_RETURN_VALUE(EPERM), // lseek
47 IOMANX_RETURN_VALUE(EPERM), // ioctl
48 IOMANX_RETURN_VALUE(EPERM), // remove
49 IOMANX_RETURN_VALUE(EPERM), // mkdir
50 IOMANX_RETURN_VALUE(EPERM), // rmdir
51 IOMANX_RETURN_VALUE(EPERM), // dopen
52 IOMANX_RETURN_VALUE(EPERM), // dclose
53 IOMANX_RETURN_VALUE(EPERM), // dread
54 IOMANX_RETURN_VALUE(EPERM), // getstat
55 IOMANX_RETURN_VALUE(EPERM), // chstat
56 IOMANX_RETURN_VALUE(EPERM), // rename
57 IOMANX_RETURN_VALUE(EPERM), // chdir
58 IOMANX_RETURN_VALUE(EPERM), // sync
59 IOMANX_RETURN_VALUE(EPERM), // mount
60 IOMANX_RETURN_VALUE(EPERM), // umount
61 IOMANX_RETURN_VALUE_S64(EPERM), // lseek64
62 &HdckDevctl, // devctl
63 IOMANX_RETURN_VALUE(EPERM), // symlink
64 IOMANX_RETURN_VALUE(EPERM), // readlink
65 IOMANX_RETURN_VALUE(EPERM), // ioctl2
66};
67
68static iomanX_iop_device_t HdckDevice = {
69 "hdck",
70 IOP_DT_FSEXT | IOP_DT_FS,
71 1,
72 "HDCK",
73 &HdckDeviceOps};
74
75struct HddInfo
76{
77 u32 sectors;
78 u32 MaxPartSize;
79 unsigned int format;
80 unsigned int status;
81};
82
84{
85 struct HddInfo HddInfo[2];
86 // When the HDD is scanned, it is scanned in both ways (forward and backward). Details on up to two erraneous partitions can be recorded.
87 u32 ErrorPartitionLBA;
88 u32 ErrorPartition2LBA;
89 u32 ErrorPartitionPrevLBA;
90 u32 ErrorPartition2PrevLBA;
91};
92
93static struct HdckPrivateData PrivateData = {
94 {
95 {0, 0, 0, 3},
96 {0, 0, 0, 3},
97 },
98 0,
99 0,
100 0,
101 0};
102
103static int HdckInit(iomanX_iop_device_t *device)
104{
105 (void)device;
106
107 return 0;
108}
109
110#ifdef HDCK_CHECK_CROSSLINK
111static int AddPartitionToList(u32 *list, unsigned int *pCount, u32 sector)
112{
113 unsigned int i;
114 int result;
115
116 for (i = 0; i < *pCount; i++) {
117 if (list[i] == sector) {
118 break;
119 }
120 }
121
122 if (i == *pCount) {
123 list[i] = sector;
124 (*pCount)++;
125 result = 0;
126 } else {
127 APA_PRINTF("found cross-linked partition: 0x%lx\n", sector);
128 result = -EEXIST;
129 }
130
131 return result;
132}
133#endif
134
135static int CheckAPAPartitionLinks(int device, apa_cache_t *clink)
136{
137 int result;
138#ifdef HDCK_CHECK_CROSSLINK
139 unsigned int partitions;
140#endif
141 apa_cache_t *clink2;
142 u32 CurrentLBA, ParentLBA;
143
144 APA_PRINTF("scan partitions.\n");
145
146 result = 0;
147 PrivateData.ErrorPartition2LBA = 0;
148 PrivateData.ErrorPartitionLBA = 0;
149 PrivateData.ErrorPartition2PrevLBA = 0;
150 PrivateData.ErrorPartitionPrevLBA = 0;
151 ParentLBA = 0;
152
153#ifdef HDCK_CHECK_CROSSLINK
154 partitions = 0;
155#endif
156 CurrentLBA = clink->header->next;
157 while (CurrentLBA != 0
158#ifdef HDCK_CHECK_CROSSLINK
159 && ((result = AddPartitionToList((u32 *)IOBuffer, &partitions, CurrentLBA)) >= 0)
160#endif
161 && (clink2 = apaCacheGetHeader(device, CurrentLBA, 0, &result)) != NULL) {
162 if (clink2->header->prev != ParentLBA) {
163 APA_PRINTF("found invalid previous partition address, fix it.\n");
164 clink2->header->prev = ParentLBA;
165 clink2->flags |= APA_CACHE_FLAG_DIRTY;
166 apaCacheFlushAllDirty(device);
167 }
168
169 ParentLBA = clink2->header->start;
170 CurrentLBA = clink2->header->next;
171 apaCacheFree(clink2);
172 }
173
174 if (result == 0) {
175 if (clink->header->prev != ParentLBA) {
176 APA_PRINTF("found invalid last partition address, fix it.\n");
177 clink->header->prev = ParentLBA;
178 clink->flags |= APA_CACHE_FLAG_DIRTY;
179 apaCacheFlushAllDirty(device);
180 }
181
182 APA_PRINTF("we do not have an error partition.\n");
183 } else {
184 APA_PRINTF("found error partition.\n");
185
186 PrivateData.ErrorPartitionLBA = CurrentLBA;
187 PrivateData.ErrorPartitionPrevLBA = ParentLBA;
188
189 // Now scan the HDD, backwards.
190 CurrentLBA = clink->header->prev;
191 ParentLBA = 0;
192#ifdef HDCK_CHECK_CROSSLINK
193 partitions = 0;
194#endif
195 while (CurrentLBA != 0
196#ifdef HDCK_CHECK_CROSSLINK
197 && ((result = AddPartitionToList((u32 *)IOBuffer, &partitions, CurrentLBA)) >= 0)
198#endif
199 && (clink2 = apaCacheGetHeader(device, CurrentLBA, 0, &result)) != NULL) {
200 if (clink2->header->next != ParentLBA) {
201 APA_PRINTF("found invalid next partition address, fix it.\n");
202
203 clink2->header->next = ParentLBA;
204 clink2->flags |= APA_CACHE_FLAG_DIRTY;
205 apaCacheFlushAllDirty(device);
206 }
207
208 ParentLBA = clink2->header->start;
209 CurrentLBA = clink2->header->prev;
210 apaCacheFree(clink2);
211 }
212
213 if (result == 0) {
214 if (clink->header->next != ParentLBA) {
215 APA_PRINTF("found invalid first partition address, fix it.\n");
216 clink->header->next = ParentLBA;
217 clink->flags |= APA_CACHE_FLAG_DIRTY;
218 apaCacheFlushAllDirty(device);
219 }
220
221 APA_PRINTF("found inconsistency, but already fixed.\n");
222 APA_PRINTF("we do not have an error partition.\n");
223
224 PrivateData.ErrorPartitionLBA = 0;
225 } else {
226 APA_PRINTF("found error partition.\n");
227
228 PrivateData.ErrorPartition2LBA = CurrentLBA;
229 PrivateData.ErrorPartition2PrevLBA = ParentLBA;
230 }
231 }
232
233 return PrivateData.ErrorPartitionLBA;
234}
235
236static void EraseSector(int unit, void *buffer, u32 lba)
237{
238 memset(buffer, 0, 512);
239 sceAtaDmaTransfer(unit, buffer, lba, 1, ATA_DIR_WRITE);
240 sceAtaFlushCache(unit);
241}
242
243static void RemoveBadPartitions(int device, apa_cache_t *clink)
244{
245 apa_cache_t *clink2;
246 int result;
247
248 APA_PRINTF("remove all partitions after unreadable one.\n");
249
250 if ((clink2 = apaCacheGetHeader(device, PrivateData.ErrorPartitionPrevLBA, 0, &result)) != NULL) {
251 clink2->header->next = 0;
252 clink->header->prev = PrivateData.ErrorPartitionPrevLBA;
253 clink2->header->flags |= APA_CACHE_FLAG_DIRTY;
254 clink->header->flags |= APA_CACHE_FLAG_DIRTY;
255
256 apaCacheFlushAllDirty(device);
257 apaCacheFree(clink2);
258
259 PrivateData.ErrorPartition2LBA = 0;
260 PrivateData.ErrorPartitionLBA = 0;
261 }
262}
263
264static void RecoverSubPartition(apa_cache_t *clink, u32 lba, u32 previous, u32 sublength, u32 substart, u16 type, int sub)
265{
266 int result;
267 apa_cache_t *clink2;
268
269 clink2 = apaCacheGetHeader(clink->device, lba, 1, &result);
270
271 APA_PRINTF("found this sub partition's main, so I recover it.\n");
272
273 memset(clink2->header, 0, sizeof(apa_header_t));
274 clink2->header->magic = APA_MAGIC;
275 clink2->header->start = lba;
276 if (lba < clink->header->prev) {
277 clink2->header->next = lba + sublength;
278 }
279 clink2->header->prev = previous;
280 clink2->header->length = sublength;
281 clink2->header->type = type;
282 clink2->header->flags = APA_FLAG_SUB;
283 clink2->header->main = substart;
284 clink2->header->number = sub;
285
286 apaGetTime(&clink2->header->created);
287
288 clink2->flags |= APA_CACHE_FLAG_DIRTY;
289
290 apaCacheFlushAllDirty(clink->device);
291 apaCacheFree(clink2);
292}
293
294// Checks if the damaged partition(s) is/are sub-partition(s) of another partition. If so, attempt to recover it/them.
295static void RecoverPartitionIfSub(int device, apa_cache_t *clink)
296{
297 int result, count, sub;
298 apa_cache_t *clink2;
299 u32 NextPartSector;
300 apa_sub_t *pSubs;
301
302 APA_PRINTF("check if error partition is belong to someone as sub partition.\n");
303
304 // Start by cycling forward through the partition list.
305 // If there is at least one more partition (other than __mbr) and the damaged partition is not the first partition.
306 if ((NextPartSector = clink->header->next) != 0 && PrivateData.ErrorPartitionLBA != clink->header->next) {
307 while ((clink2 = apaCacheGetHeader(device, NextPartSector, 0, &result)) != NULL) {
308 if (clink2->header->type && !(clink2->header->flags & APA_FLAG_SUB)) {
309 for (count = 1, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++, count++) {
310 if (PrivateData.ErrorPartitionLBA && pSubs->start == PrivateData.ErrorPartitionLBA) {
311 RecoverSubPartition(clink, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, pSubs->length, clink2->header->start, clink2->header->type, count);
312
313 if (PrivateData.ErrorPartition2LBA == PrivateData.ErrorPartitionLBA) {
314 PrivateData.ErrorPartition2LBA = 0;
315 }
316 PrivateData.ErrorPartitionLBA = 0;
317 }
318
319 if (PrivateData.ErrorPartition2LBA && pSubs->start == PrivateData.ErrorPartition2LBA) {
320 RecoverSubPartition(clink, PrivateData.ErrorPartition2LBA, PrivateData.ErrorPartitionLBA, pSubs->length, clink2->header->start, clink2->header->type, count);
321
322 PrivateData.ErrorPartition2LBA = 0;
323 }
324 }
325 }
326
327 NextPartSector = clink2->header->next;
328 apaCacheFree(clink2);
329
330 if (!PrivateData.ErrorPartitionLBA && !PrivateData.ErrorPartition2LBA) {
331 return;
332 }
333
334 if (!NextPartSector || NextPartSector == PrivateData.ErrorPartitionLBA) {
335 break;
336 }
337 }
338 }
339
340 /* Cycle backward through the partition list.
341 If there is at least one more partition (other than __mbr) and the damaged partition is not the last partition. */
342 if ((NextPartSector = clink->header->prev) != 0 && clink->header->prev != PrivateData.ErrorPartition2LBA) {
343 while ((clink2 = apaCacheGetHeader(device, NextPartSector, 0, &result)) != NULL) {
344 if (clink2->header->type && !(clink2->header->flags & APA_FLAG_SUB)) {
345 for (count = 1, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++, count++) {
346 if (PrivateData.ErrorPartitionLBA && pSubs->start == PrivateData.ErrorPartitionLBA) {
347 RecoverSubPartition(clink, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, pSubs->length, clink2->header->start, clink2->header->type, count);
348
349 if (PrivateData.ErrorPartition2LBA == PrivateData.ErrorPartitionLBA) {
350 PrivateData.ErrorPartition2LBA = 0;
351 }
352 PrivateData.ErrorPartitionLBA = 0;
353 }
354
355 if (PrivateData.ErrorPartition2LBA && pSubs->start == PrivateData.ErrorPartition2LBA) {
356 RecoverSubPartition(clink, PrivateData.ErrorPartition2LBA, PrivateData.ErrorPartitionLBA, pSubs->length, clink2->header->start, clink2->header->type, count);
357
358 PrivateData.ErrorPartition2LBA = 0;
359 }
360 }
361 }
362
363 NextPartSector = clink2->header->prev;
364 apaCacheFree(clink2);
365
366 if (!PrivateData.ErrorPartitionLBA && !PrivateData.ErrorPartition2LBA) {
367 return;
368 }
369
370 if (!NextPartSector || NextPartSector == PrivateData.ErrorPartitionLBA) {
371 break;
372 }
373 }
374 }
375}
376
377static apa_cache_t *apaCreateAlignedEmptyPartition(apa_cache_t *clink, u32 lba, u32 length)
378{
379 apa_cache_t *result;
380
381 for (length >>= 1; 0x0003FFFF < length; length >>= 1) {
382 if (lba % length == 0) {
383 result = apaRemovePartition(clink->device, lba, lba + length, clink->header->start, length);
384 clink->header->next = lba;
385 clink->flags |= APA_CACHE_FLAG_DIRTY;
386 apaCacheFlushAllDirty(clink->device);
387 apaCacheFree(clink);
388
389 return result;
390 }
391 }
392
393 return NULL;
394}
395
396static void MarkUnreadablePartionAsEmpty(int device, u32 lba, u32 parent, u32 length)
397{
398 apa_cache_t *clink;
399 u32 new_length;
400 int result;
401
402 new_length = 0;
403 clink = apaCacheGetHeader(device, parent, 0, &result);
404 APA_PRINTF("make unreadable partition as empty.\n");
405
406 if (clink != NULL) {
407 while (length != 0) {
408 int i;
409
410 for (i = 31; i >= 0; i--) {
411 if ((new_length = ((u32)1) << i) & length) {
412 break;
413 }
414 }
415
416 if (lba % new_length) {
417 clink = apaCreateAlignedEmptyPartition(clink, lba, new_length);
418 } else {
419 apaRemovePartition(device, lba, lba + new_length, clink->header->start, new_length);
420 clink->header->next = lba;
421 clink->flags |= APA_CACHE_FLAG_DIRTY;
422 apaCacheFlushAllDirty(device);
423 apaCacheFree(clink);
424 }
425
426 length -= clink->header->length;
427 }
428
429 apaCacheFree(clink);
430 PrivateData.ErrorPartition2LBA = 0;
431 PrivateData.ErrorPartitionLBA = 0;
432 }
433}
434
435static void DeleteFreePartitions(int device, apa_cache_t *clink)
436{
437 apa_cache_t *clink2;
438 int result;
439 u32 sector;
440
441 sector = clink->header->next;
442 while (sector != 0 && (clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
443 if (clink2->header->type == 0) {
444 if ((clink2 = apaDeleteFixPrev(clink2, &result)) == NULL) {
445 break;
446 }
447 }
448
449 sector = clink2->header->next;
450 apaCacheFree(clink2);
451 }
452}
453
454// Generates lists of all main and sub-partitions on the disk.
455static int ReadPartitionMap(int device, apa_cache_t *clink, int *pMainCount, int *pSubCount)
456{
457 int result;
458 apa_cache_t *clink2;
459 u32 sector, *MainMap, *SubMap;
460
461 *pMainCount = 0;
462 *pSubCount = 0;
463 result = 0;
464 sector = clink->header->next;
465 MainMap = (u32 *)IOBuffer;
466 SubMap = (u32 *)IOBuffer2;
467 while (sector != 0) {
468 if ((clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
469 if (clink2->header->type) {
470 if (!(clink2->header->flags & APA_FLAG_SUB)) {
471 APA_PRINTF("main, start %08lx, nsector %08lx, nsub %ld, id %s\n", clink2->header->start, clink2->header->length, clink2->header->nsub, clink2->header->id);
472
473 MainMap[(*pMainCount)] = clink2->header->start;
474 (*pMainCount)++;
475 }
476 if (clink2->header->type && clink2->header->flags & APA_FLAG_SUB) {
477 APA_PRINTF("sub , start %08lx, nsector %08lx, num %2ld, main %08lx\n", clink2->header->start, clink2->header->length, clink2->header->number, clink2->header->main);
478 SubMap[(*pSubCount)] = clink2->header->start;
479 (*pSubCount)++;
480 }
481 }
482
483 sector = clink2->header->next;
484 apaCacheFree(clink2);
485 } else {
486 break;
487 }
488 }
489
490 return result;
491}
492
493// Goes through the partitions and checks the relationships between the main and sub-partitions.
494static int CheckPartitions(int device, apa_cache_t *clink)
495{
496 int result, MainCount, SubCount;
497
498 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
499 int i, sub, count;
500 apa_cache_t *clink2, *clink_sub;
501
502 APA_PRINTF("check main partitions.\n");
503
504 for (i = 0; i < MainCount && result == 0; i++) {
505 if ((clink2 = apaCacheGetHeader(device, ((u32 *)IOBuffer)[i], 0, &result)) != NULL) {
506 int missing_sub_found;
507 apa_sub_t *pSubs;
508
509 // Check through the list of sub-partitions, to see if a the sub-partition belongs to a main partition.
510 for (missing_sub_found = 0, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++) {
511 int flag;
512
513 for (flag = 0, count = 0; count < SubCount; count++) {
514 if (pSubs->start == ((u32 *)IOBuffer2)[count]) {
515 flag = 1;
516 break;
517 }
518 }
519
520 if (!flag) {
521 // Sub-partition does not belong to anything.
522 APA_PRINTF("missing sub partition found.\n");
523
524 if (!missing_sub_found) {
525 clink2->header->nsub = sub;
526 clink2->flags |= APA_CACHE_FLAG_DIRTY;
527 missing_sub_found = 1; //"missing sub" found.
528 apaCacheFlushAllDirty(device);
529 }
530 } else {
531 // Sub-partition belongs to something, but follows a missing partition.
532 if (missing_sub_found) {
533 APA_PRINTF("remove sub partition follows missing partition.\n");
534
535 if ((clink_sub = apaCacheGetHeader(device, pSubs->start, 0, &result)) != NULL) {
536 result = apaDelete(clink_sub);
537 }
538 }
539 } // Otherwise, the sub-partition is okay.
540 }
541
542 apaCacheFree(clink2);
543 }
544 }
545
546 if (result >= 0) {
547 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
548 u32 *ptr;
549
550 APA_PRINTF("check sub partitions.\n");
551
552 for (sub = 0, ptr = (u32 *)IOBuffer2; sub < SubCount && result == 0; ptr++, sub++) {
553 // Check through the list of main partitions, to see if the sub-partition belongs to a main partition.
554 if ((clink2 = apaCacheGetHeader(device, *ptr, 0, &result)) != NULL) {
555 for (i = 0; ((u32 *)IOBuffer)[i] != clink2->header->main && i < MainCount; i++)
556 ;
557
558 if (MainCount == i) {
559 APA_PRINTF("this sub(start = %08lx)is not belong to anyone, remove it.\n", clink2->header->start);
560 if ((result = apaDelete(clink2)) != 0) {
561 APA_PRINTF("remove partition failed.\n");
562 }
563 } else {
564 // Check if the sub-partition belongs to the main partition's sub-partition list.
565 if ((clink_sub = apaCacheGetHeader(device, clink2->header->main, 0, &result)) != NULL) {
566 for (count = 0; (u32)count < clink2->header->nsub; count++) {
567 if (clink_sub->header->subs[count].start == *ptr) {
568 break;
569 }
570 }
571
572 if (clink_sub->header->nsub == (u32)count) {
573 APA_PRINTF("this subpartition is not belong to sub list.\n");
574 apaDelete(clink2);
575 apaCacheFree(clink_sub);
576 } else {
577 apaCacheFree(clink_sub);
578 apaCacheFree(clink2);
579 }
580 } else {
581 apaCacheFree(clink2);
582 }
583 }
584 } else {
585 break;
586 }
587 }
588 }
589 }
590 }
591
592 return result;
593}
594
595static int HdckDevctl(iomanX_iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
596{
597 int result, badParts;
598 apa_cache_t *clink;
599
600 (void)name;
601 (void)cmd;
602 (void)arg;
603 (void)arglen;
604 (void)buf;
605 (void)buflen;
606
607 if (PrivateData.HddInfo[fd->unit].status != 0) {
608 return -ENXIO;
609 }
610
611 if ((clink = apaCacheGetHeader(fd->unit, APA_SECTOR_MBR, 0, &result)) != NULL) {
612 badParts = 0;
613 while (CheckAPAPartitionLinks(fd->unit, clink) != 0) {
614 // Both pointers point to the same partition.
615 if (PrivateData.ErrorPartitionLBA == PrivateData.ErrorPartition2LBA) {
616 APA_PRINTF("only one partition has problem, try to fix it.\n");
617 RecoverPartitionIfSub(fd->unit, clink);
618
619 // If the error is still there, decide on how to delete the partition.
620 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
621 // If the partition is not the last partition, turn it into an empty partition. Otherwise, delete it.
622 if (clink->header->prev != PrivateData.ErrorPartitionLBA) {
623 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
624 } else {
625 RemoveBadPartitions(fd->unit, clink);
626 }
627 } else {
628 continue;
629 }
630 // More than one partition in-between the pointers are bad.
631 } else if (PrivateData.ErrorPartitionLBA < PrivateData.ErrorPartition2LBA) {
632 APA_PRINTF("two or more partitions have problem, try to fix it.\n");
633
634 RecoverPartitionIfSub(fd->unit, clink);
635
636 // If the error is still there, decide on how to delete the partition.
637 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
638 // If both of the partitions are not the last partition, turn them both into empty partitions. Otherwise, delete them.
639 if (clink->header->prev != PrivateData.ErrorPartitionLBA && clink->header->prev != PrivateData.ErrorPartition2LBA) {
640 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
641 } else {
642 RemoveBadPartitions(fd->unit, clink);
643 }
644 } else {
645 continue;
646 }
647 // The pointers overlap, making it impossible to tell where the bad partitions certainly are. The only solution is to nuke 'em all.
648 } else {
649 APA_PRINTF("partition table completely inconsistent.\n");
650 RemoveBadPartitions(fd->unit, clink);
651 }
652
653 // If there are more than 8 bad partitions, abort.
654 badParts++;
655 if (badParts == 9) {
656 goto check_end;
657 }
658 }
659
660 EraseSector(fd->unit, IOBuffer, APA_SECTOR_SECTOR_ERROR); // Erase the error sector record.
661 DeleteFreePartitions(fd->unit, clink);
662 result = CheckPartitions(fd->unit, clink);
663
664 check_end:
665 apaCacheFree(clink);
666 APA_PRINTF("done\n");
667 } else {
668 APA_PRINTF("cannot read mbr partition, I cannot continue.\n");
669 }
670
671 return result;
672}
673
674int APA_ENTRYPOINT(int argc, char **argv)
675{
676 apa_ps2time_t time;
677 ata_devinfo_t *pDevInfo;
678 int i;
679
680 (void)argc;
681 (void)argv;
682
683 if (apaGetTime(&time) != 0) {
684 APA_PRINTF("error: could not get date\n");
685 return MODULE_NO_RESIDENT_END;
686 }
687
688 APA_PRINTF("%02d:%02d:%02d %02d/%02d/%d\n", time.hour, time.min, time.sec, time.month, time.day, time.year);
689
690 for (i = 0; i < 2; i++) {
691 if ((pDevInfo = sceAtaInit(i)) == NULL) {
692 APA_PRINTF("error: ata initialization failed.\n");
693 return MODULE_NO_RESIDENT_END;
694 }
695
696 if (pDevInfo->exists && !pDevInfo->has_packet) {
697 PrivateData.HddInfo[i].status--;
698 PrivateData.HddInfo[i].sectors = pDevInfo->total_sectors;
699
700 PrivateData.HddInfo[i].MaxPartSize = apaGetPartitionMax(pDevInfo->total_sectors);
701 if (HdckUnlockHdd(i) == 0) {
702 PrivateData.HddInfo[i].status--;
703 }
704
705 APA_PRINTF("disk%d: 0x%08lx sectors, max 0x%08lx\n", i, PrivateData.HddInfo[i].sectors, PrivateData.HddInfo[i].MaxPartSize);
706 }
707 }
708
709 apaCacheInit(0x100);
710 for (i = 0; i < 2; i++) {
711 if (PrivateData.HddInfo[i].status < 2) {
712 if (apaJournalRestore(i) != 0) {
713 return MODULE_NO_RESIDENT_END;
714 }
715
716 if (apaGetFormat(i, (int *)&PrivateData.HddInfo[i].format)) {
717 PrivateData.HddInfo[i].status--;
718 }
719 }
720 }
721
722 iomanX_DelDrv(HdckDevice.name);
723 if (iomanX_AddDrv(&HdckDevice) == 0) {
724 APA_PRINTF("driver start.\n");
725 return MODULE_RESIDENT_END;
726 }
727
728 return MODULE_NO_RESIDENT_END;
729}
s32 exists
Definition atad.h:29
u32 total_sectors
Definition atad.h:33
s32 has_packet
Definition atad.h:31
#define EEXIST
Definition errno.h:53
#define ENXIO
Definition errno.h:31
#define EPERM
Definition errno.h:21
#define APA_FLAG_SUB
Definition hdd-ioctl.h:51
#define IOP_DT_FSEXT
Definition iomanX.h:66
Definition hdck.c:76
u32 count
start sector of fragmented bd/file