PS2SDK
PS2 Homebrew Libraries
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
25 IRX_ID("hdck", APA_MODVER_MAJOR, APA_MODVER_MINOR);
26 #endif
27 
28 // Function prototypes
29 static int HdckInit(iomanX_iop_device_t *device);
30 static int HdckDevctl(iomanX_iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
31 
32 static u8 IOBuffer[128 * 512];
33 static u8 IOBuffer2[128 * 512];
34 
35 IOMANX_RETURN_VALUE_IMPL(0);
36 IOMANX_RETURN_VALUE_IMPL(EPERM);
37 
38 static 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 
68 static iomanX_iop_device_t HdckDevice = {
69  "hdck",
70  IOP_DT_FSEXT | IOP_DT_FS,
71  1,
72  "HDCK",
73  &HdckDeviceOps};
74 
75 struct 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 
93 static struct HdckPrivateData PrivateData = {
94  {
95  {0, 0, 0, 3},
96  {0, 0, 0, 3},
97  },
98  0,
99  0,
100  0,
101  0};
102 
103 static int HdckInit(iomanX_iop_device_t *device)
104 {
105  (void)device;
106 
107  return 0;
108 }
109 
110 #ifdef HDCK_CHECK_CROSSLINK
111 static 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 
135 static 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 
236 static 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 
243 static 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 
264 static 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.
295 static 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 
377 static 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 
400 static 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 
439 static 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.
459 static 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.
498 static 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 
599 static 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 
678 int 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 }
iomanX.h
apa_sub_t
Definition: libapa.h:56
apa_header_t
Definition: libapa.h:62
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
_ata_devinfo::has_packet
s32 has_packet
Definition: xatapi.c:43
_ata_devinfo
Definition: xatapi.c:40
_iomanX_iop_file
Definition: iomanX.h:70
sysclib.h
EPERM
#define EPERM
Definition: errno.h:21
atad.h
ENXIO
#define ENXIO
Definition: errno.h:31
sapa_cache
Definition: libapa.h:120
loadcore.h
HdckPrivateData
Definition: hdck.c:83
apa_ps2time_t
Definition: libapa.h:42
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
hdd-ioctl.h
APA_FLAG_SUB
#define APA_FLAG_SUB
Definition: hdd-ioctl.h:51
_ata_devinfo::exists
s32 exists
Definition: xatapi.c:42
irx.h
_iomanX_iop_device_ops
Definition: iomanX.h:95
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
EEXIST
#define EEXIST
Definition: errno.h:53
HddInfo
Definition: hdck.c:75
_ata_devinfo::total_sectors
u32 total_sectors
Definition: xatapi.c:44
errno.h