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 u32 minsize = 0x3FFFF; // 128MB
381#ifdef APA_8MB_PARTITION_SIZE
382 minsize = 0x3FFF; // 8MB
383#endif
384
385 for (length >>= 1; minsize < length; length >>= 1) {
386 if (lba % length == 0) {
387 result = apaRemovePartition(clink->device, lba, lba + length, clink->header->start, length);
388 clink->header->next = lba;
389 clink->flags |= APA_CACHE_FLAG_DIRTY;
390 apaCacheFlushAllDirty(clink->device);
391 apaCacheFree(clink);
392
393 return result;
394 }
395 }
396
397 return NULL;
398}
399
400static void MarkUnreadablePartionAsEmpty(int device, u32 lba, u32 parent, u32 length)
401{
402 apa_cache_t *clink;
403 u32 new_length;
404 int result;
405
406 new_length = 0;
407 clink = apaCacheGetHeader(device, parent, 0, &result);
408 APA_PRINTF("make unreadable partition as empty.\n");
409
410 if (clink != NULL) {
411 while (length != 0) {
412 int i;
413
414 for (i = 31; i >= 0; i--) {
415 if ((new_length = ((u32)1) << i) & length) {
416 break;
417 }
418 }
419
420 if (lba % new_length) {
421 clink = apaCreateAlignedEmptyPartition(clink, lba, new_length);
422 } else {
423 apaRemovePartition(device, lba, lba + new_length, clink->header->start, new_length);
424 clink->header->next = lba;
425 clink->flags |= APA_CACHE_FLAG_DIRTY;
426 apaCacheFlushAllDirty(device);
427 apaCacheFree(clink);
428 }
429
430 length -= clink->header->length;
431 }
432
433 apaCacheFree(clink);
434 PrivateData.ErrorPartition2LBA = 0;
435 PrivateData.ErrorPartitionLBA = 0;
436 }
437}
438
439static void DeleteFreePartitions(int device, apa_cache_t *clink)
440{
441 apa_cache_t *clink2;
442 int result;
443 u32 sector;
444
445 sector = clink->header->next;
446 while (sector != 0 && (clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
447 if (clink2->header->type == 0) {
448 if ((clink2 = apaDeleteFixPrev(clink2, &result)) == NULL) {
449 break;
450 }
451 }
452
453 sector = clink2->header->next;
454 apaCacheFree(clink2);
455 }
456}
457
458// Generates lists of all main and sub-partitions on the disk.
459static int ReadPartitionMap(int device, apa_cache_t *clink, int *pMainCount, int *pSubCount)
460{
461 int result;
462 apa_cache_t *clink2;
463 u32 sector, *MainMap, *SubMap;
464
465 *pMainCount = 0;
466 *pSubCount = 0;
467 result = 0;
468 sector = clink->header->next;
469 MainMap = (u32 *)IOBuffer;
470 SubMap = (u32 *)IOBuffer2;
471 while (sector != 0) {
472 if ((clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
473 if (clink2->header->type) {
474 if (!(clink2->header->flags & APA_FLAG_SUB)) {
475 APA_PRINTF("main, start %08lx, nsector %08lx, nsub %ld, id %s\n", clink2->header->start, clink2->header->length, clink2->header->nsub, clink2->header->id);
476
477 MainMap[(*pMainCount)] = clink2->header->start;
478 (*pMainCount)++;
479 }
480 if (clink2->header->type && clink2->header->flags & APA_FLAG_SUB) {
481 APA_PRINTF("sub , start %08lx, nsector %08lx, num %2ld, main %08lx\n", clink2->header->start, clink2->header->length, clink2->header->number, clink2->header->main);
482 SubMap[(*pSubCount)] = clink2->header->start;
483 (*pSubCount)++;
484 }
485 }
486
487 sector = clink2->header->next;
488 apaCacheFree(clink2);
489 } else {
490 break;
491 }
492 }
493
494 return result;
495}
496
497// Goes through the partitions and checks the relationships between the main and sub-partitions.
498static int CheckPartitions(int device, apa_cache_t *clink)
499{
500 int result, MainCount, SubCount;
501
502 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
503 int i, sub, count;
504 apa_cache_t *clink2, *clink_sub;
505
506 APA_PRINTF("check main partitions.\n");
507
508 for (i = 0; i < MainCount && result == 0; i++) {
509 if ((clink2 = apaCacheGetHeader(device, ((u32 *)IOBuffer)[i], 0, &result)) != NULL) {
510 int missing_sub_found;
511 apa_sub_t *pSubs;
512
513 // Check through the list of sub-partitions, to see if a the sub-partition belongs to a main partition.
514 for (missing_sub_found = 0, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++) {
515 int flag;
516
517 for (flag = 0, count = 0; count < SubCount; count++) {
518 if (pSubs->start == ((u32 *)IOBuffer2)[count]) {
519 flag = 1;
520 break;
521 }
522 }
523
524 if (!flag) {
525 // Sub-partition does not belong to anything.
526 APA_PRINTF("missing sub partition found.\n");
527
528 if (!missing_sub_found) {
529 clink2->header->nsub = sub;
530 clink2->flags |= APA_CACHE_FLAG_DIRTY;
531 missing_sub_found = 1; //"missing sub" found.
532 apaCacheFlushAllDirty(device);
533 }
534 } else {
535 // Sub-partition belongs to something, but follows a missing partition.
536 if (missing_sub_found) {
537 APA_PRINTF("remove sub partition follows missing partition.\n");
538
539 if ((clink_sub = apaCacheGetHeader(device, pSubs->start, 0, &result)) != NULL) {
540 result = apaDelete(clink_sub);
541 }
542 }
543 } // Otherwise, the sub-partition is okay.
544 }
545
546 apaCacheFree(clink2);
547 }
548 }
549
550 if (result >= 0) {
551 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
552 u32 *ptr;
553
554 APA_PRINTF("check sub partitions.\n");
555
556 for (sub = 0, ptr = (u32 *)IOBuffer2; sub < SubCount && result == 0; ptr++, sub++) {
557 // Check through the list of main partitions, to see if the sub-partition belongs to a main partition.
558 if ((clink2 = apaCacheGetHeader(device, *ptr, 0, &result)) != NULL) {
559 for (i = 0; ((u32 *)IOBuffer)[i] != clink2->header->main && i < MainCount; i++)
560 ;
561
562 if (MainCount == i) {
563 APA_PRINTF("this sub(start = %08lx)is not belong to anyone, remove it.\n", clink2->header->start);
564 if ((result = apaDelete(clink2)) != 0) {
565 APA_PRINTF("remove partition failed.\n");
566 }
567 } else {
568 // Check if the sub-partition belongs to the main partition's sub-partition list.
569 if ((clink_sub = apaCacheGetHeader(device, clink2->header->main, 0, &result)) != NULL) {
570 for (count = 0; (u32)count < clink2->header->nsub; count++) {
571 if (clink_sub->header->subs[count].start == *ptr) {
572 break;
573 }
574 }
575
576 if (clink_sub->header->nsub == (u32)count) {
577 APA_PRINTF("this subpartition is not belong to sub list.\n");
578 apaDelete(clink2);
579 apaCacheFree(clink_sub);
580 } else {
581 apaCacheFree(clink_sub);
582 apaCacheFree(clink2);
583 }
584 } else {
585 apaCacheFree(clink2);
586 }
587 }
588 } else {
589 break;
590 }
591 }
592 }
593 }
594 }
595
596 return result;
597}
598
599static int HdckDevctl(iomanX_iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
600{
601 int result, badParts;
602 apa_cache_t *clink;
603
604 (void)name;
605 (void)cmd;
606 (void)arg;
607 (void)arglen;
608 (void)buf;
609 (void)buflen;
610
611 if (PrivateData.HddInfo[fd->unit].status != 0) {
612 return -ENXIO;
613 }
614
615 if ((clink = apaCacheGetHeader(fd->unit, APA_SECTOR_MBR, 0, &result)) != NULL) {
616 badParts = 0;
617 while (CheckAPAPartitionLinks(fd->unit, clink) != 0) {
618 // Both pointers point to the same partition.
619 if (PrivateData.ErrorPartitionLBA == PrivateData.ErrorPartition2LBA) {
620 APA_PRINTF("only one partition has problem, try to fix it.\n");
621 RecoverPartitionIfSub(fd->unit, clink);
622
623 // If the error is still there, decide on how to delete the partition.
624 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
625 // If the partition is not the last partition, turn it into an empty partition. Otherwise, delete it.
626 if (clink->header->prev != PrivateData.ErrorPartitionLBA) {
627 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
628 } else {
629 RemoveBadPartitions(fd->unit, clink);
630 }
631 } else {
632 continue;
633 }
634 // More than one partition in-between the pointers are bad.
635 } else if (PrivateData.ErrorPartitionLBA < PrivateData.ErrorPartition2LBA) {
636 APA_PRINTF("two or more partitions have problem, try to fix it.\n");
637
638 RecoverPartitionIfSub(fd->unit, clink);
639
640 // If the error is still there, decide on how to delete the partition.
641 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
642 // If both of the partitions are not the last partition, turn them both into empty partitions. Otherwise, delete them.
643 if (clink->header->prev != PrivateData.ErrorPartitionLBA && clink->header->prev != PrivateData.ErrorPartition2LBA) {
644 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
645 } else {
646 RemoveBadPartitions(fd->unit, clink);
647 }
648 } else {
649 continue;
650 }
651 // The pointers overlap, making it impossible to tell where the bad partitions certainly are. The only solution is to nuke 'em all.
652 } else {
653 APA_PRINTF("partition table completely inconsistent.\n");
654 RemoveBadPartitions(fd->unit, clink);
655 }
656
657 // If there are more than 8 bad partitions, abort.
658 badParts++;
659 if (badParts == 9) {
660 goto check_end;
661 }
662 }
663
664 EraseSector(fd->unit, IOBuffer, APA_SECTOR_SECTOR_ERROR); // Erase the error sector record.
665 DeleteFreePartitions(fd->unit, clink);
666 result = CheckPartitions(fd->unit, clink);
667
668 check_end:
669 apaCacheFree(clink);
670 APA_PRINTF("done\n");
671 } else {
672 APA_PRINTF("cannot read mbr partition, I cannot continue.\n");
673 }
674
675 return result;
676}
677
678int APA_ENTRYPOINT(int argc, char **argv)
679{
680 apa_ps2time_t time;
681 ata_devinfo_t *pDevInfo;
682 int i;
683
684 (void)argc;
685 (void)argv;
686
687 if (apaGetTime(&time) != 0) {
688 APA_PRINTF("error: could not get date\n");
689 return MODULE_NO_RESIDENT_END;
690 }
691
692 APA_PRINTF("%02d:%02d:%02d %02d/%02d/%d\n", time.hour, time.min, time.sec, time.month, time.day, time.year);
693
694 for (i = 0; i < 2; i++) {
695 if ((pDevInfo = sceAtaInit(i)) == NULL) {
696 APA_PRINTF("error: ata initialization failed.\n");
697 return MODULE_NO_RESIDENT_END;
698 }
699
700 if (pDevInfo->exists && !pDevInfo->has_packet) {
701 PrivateData.HddInfo[i].status--;
702 PrivateData.HddInfo[i].sectors = pDevInfo->total_sectors;
703
704 PrivateData.HddInfo[i].MaxPartSize = apaGetPartitionMax(pDevInfo->total_sectors);
705 if (HdckUnlockHdd(i) == 0) {
706 PrivateData.HddInfo[i].status--;
707 }
708
709 APA_PRINTF("disk%d: 0x%08lx sectors, max 0x%08lx\n", i, PrivateData.HddInfo[i].sectors, PrivateData.HddInfo[i].MaxPartSize);
710 }
711 }
712
713 apaCacheInit(0x100);
714 for (i = 0; i < 2; i++) {
715 if (PrivateData.HddInfo[i].status < 2) {
716 if (apaJournalRestore(i) != 0) {
717 return MODULE_NO_RESIDENT_END;
718 }
719
720 if (apaGetFormat(i, (int *)&PrivateData.HddInfo[i].format)) {
721 PrivateData.HddInfo[i].status--;
722 }
723 }
724 }
725
726 iomanX_DelDrv(HdckDevice.name);
727 if (iomanX_AddDrv(&HdckDevice) == 0) {
728 APA_PRINTF("driver start.\n");
729 return MODULE_RESIDENT_END;
730 }
731
732 return MODULE_NO_RESIDENT_END;
733}
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