PS2SDK
PS2 Homebrew Libraries
fsck.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 <errno.h>
12 #include <irx.h>
13 #include <iomanX.h>
14 #include <hdd-ioctl.h>
15 #include <loadcore.h>
16 #include <kerr.h>
17 #include <thbase.h>
18 #include <thevent.h>
19 #include <stdio.h>
20 #include <sysclib.h>
21 
22 #include "libpfs.h"
23 #include "bitmap_fsck.h"
24 #include "misc_fsck.h"
25 
26 #include "fsck-ioctl.h"
27 
28 #ifdef _IOP
29 IRX_ID("fsck", PFS_MAJOR, PFS_MINOR);
30 #endif
31 
33 {
34  struct fsckStatus status; // 0x00
35  int hasError; // 0x1C
36  int stopFlag; // 0x20
37 };
38 
39 static int fsckWriteEnabled;
40 static int fsckAutoMode;
41 static int fsckVerbosityLevel;
42 extern u32 pfsMetaSize;
43 extern u32 pfsBlockSize;
44 static pfs_mount_t MainPFSMount = {0}; // FIXME: if not explicitly initialized to 0, the generated IRX would somehow have garbage in this structure.
45 
46 #define IO_BUFFER_SIZE 256
47 #define IO_BUFFER_SIZE_BYTES (IO_BUFFER_SIZE * 512)
48 
49 static struct fsckRuntimeData fsckRuntimeData;
50 static u8 IOBuffer[IO_BUFFER_SIZE_BYTES];
51 
52 #define FSCK_NUM_SUPPORTED_DEVICES 1
53 #define FSCK_MAX_PATH_LEVELS 64
54 #define FSCK_MAX_PATH_SEG_LENGTH 256
55 
56 static int fsckEventFlagID;
57 static int fsckThreadID;
58 static char fsckPathBuffer[FSCK_MAX_PATH_LEVELS][FSCK_MAX_PATH_SEG_LENGTH];
59 
60 static u32 ZoneSizes[0x41]; // Contains the sizes of all zones, in units of 512-byte sectors.
61 static u32 ZoneMap[0x41]; // Contains the starting addresses of all zones, in units of blocks.
62 
63 // 0x00000000
64 const char *fsckGetChar(void)
65 {
66  static char buffer[80];
67  const char *pChar;
68 
69 #ifdef _IOP
70  // cppcheck-suppress getsCalled
71  if (gets(buffer) != NULL)
72 #else
73  if (fgets(buffer, sizeof(buffer), stdin) != NULL)
74 #endif
75  {
76  for (pChar = buffer; *pChar != '\0'; pChar++) {
77  if (isgraph(*(const unsigned char *)pChar)) {
78  break;
79  }
80  }
81  } else {
82  pChar = NULL;
83  }
84 
85  return pChar;
86 }
87 
88 // 0x00000068
89 static int fsckPromptUserAction(const char *description, int mode)
90 {
91  int result;
92 
93  fsckRuntimeData.status.errorCount++;
94 
95  if (fsckWriteEnabled != 0) {
96  if (fsckAutoMode != 0) {
97  printf("\n");
98  if (mode) {
99  fsckRuntimeData.status.fixedErrorCount++;
100  } else {
101  fsckRuntimeData.hasError = 1;
102  }
103 
104  result = mode;
105  } else {
106  unsigned char choice;
107 
108  printf("%s (%s)? ", description, mode == 0 ? "n/y" : "y/n");
109  do {
110  choice = *fsckGetChar();
111  } while (choice != 'n' && choice != 'y');
112 
113  if (choice == 'y') {
114  fsckRuntimeData.status.fixedErrorCount++;
115  result = 1;
116  } else {
117  fsckRuntimeData.hasError = 1;
118  result = 0;
119  }
120  }
121  } else {
122  printf("\n");
123  fsckRuntimeData.hasError = 1;
124  result = 0;
125  }
126 
127  return result;
128 }
129 
130 #ifndef FSCK100
131 static int fsckPromptUserAction2(const char *description, int mode)
132 {
133  int result;
134 
135  if (fsckWriteEnabled != 0) {
136  if (fsckAutoMode != 0) {
137  printf("\n");
138  if (mode == 0) {
139  fsckRuntimeData.hasError = 1;
140  }
141 
142  result = mode;
143  } else {
144  unsigned char choice;
145 
146  printf("%s (%s)? ", description, mode == 0 ? "n/y" : "y/n");
147  do {
148  choice = *fsckGetChar();
149  } while (choice != 'n' && choice != 'y');
150 
151  if (choice == 'y') {
152  result = 1;
153  } else {
154  fsckRuntimeData.hasError = 1;
155  result = 0;
156  }
157  }
158  } else {
159  printf("\n");
160  fsckRuntimeData.hasError = 1;
161  result = 0;
162  }
163 
164  return result;
165 }
166 #endif
167 
168 // 0x00002654
169 static int DisplayUsageHelp(void)
170 {
171  PFS_PRINTF("error: Usage: fsck [-n <num>]\n");
172  return MODULE_NO_RESIDENT_END;
173 }
174 
175 #ifndef FSCK100
176 static int fsckCheckExtendedAttribute(pfs_mount_t *mount)
177 {
178  int remaining, size, result;
179 
180  iomanX_lseek(mount->fd, 0, SEEK_SET);
181  for (result = 0, remaining = 0x1FF8; remaining != 0; remaining -= size) {
182  size = (remaining > IO_BUFFER_SIZE) ? IO_BUFFER_SIZE : remaining;
183 
184  if (iomanX_read(mount->fd, IOBuffer, size * 512) == -EIO) {
185  PFS_PRINTF("cannot read extended attribute %d\n", -EIO);
186  if (fsckPromptUserAction(" nullify extended attribute", 1) == 0) {
187  break;
188  }
189 
190  memset(IOBuffer, 0, IO_BUFFER_SIZE_BYTES);
191  iomanX_lseek(mount->fd, 0, SEEK_SET);
192  for (remaining = 0x1FF8; remaining != 0; remaining -= size) {
193  size = (remaining > IO_BUFFER_SIZE) ? IO_BUFFER_SIZE : remaining;
194 
195  if ((result = iomanX_write(mount->fd, IOBuffer, size * 512)) < 0) {
196  PFS_PRINTF("error: could not nullify extended attribute.\n");
197  break;
198  }
199  }
200 
201  break;
202  }
203  }
204 
205  return result;
206 }
207 #endif
208 
209 static int fsckCheckDirentryInode(pfs_cache_t *clink);
210 
211 // 0x0000183c
212 static pfs_cache_t *CheckRootDirectory(pfs_mount_t *mount)
213 {
214  pfs_cache_t *pResultClink, *clink;
215  int result;
216 
217  if ((clink = pfsInodeGetData(mount, mount->root_dir.subpart, mount->root_dir.number, &result)) != NULL) {
218  if (fsckVerbosityLevel >= 2) {
219  printf("/: ");
220  }
221  if (fsckCheckDirentryInode(clink) == 0) {
222  pResultClink = clink;
223  } else {
224  pfsCacheFree(clink);
225  pResultClink = NULL;
226  }
227  } else {
228  pResultClink = NULL;
229  }
230 
231  return pResultClink;
232 }
233 
234 // 0x000007a8
235 static void pfsPrintPWD(void)
236 {
237  int i;
238  char *pName;
239 
240  for (i = 0, pName = fsckPathBuffer[0]; (u32)i < fsckRuntimeData.status.PWDLevel; i++, pName += FSCK_MAX_PATH_SEG_LENGTH) {
241  printf("/%s", pName);
242  }
243 
244  if (i == 0) {
245  printf("/");
246  }
247 }
248 
249 // 0x000008c8
250 static int pfsInitDirEnt(pfs_mount_t *mount, u16 subpart, u32 inodeNumber, u32 number, int isDir)
251 {
252  pfs_cache_t *clink;
253  int result;
254 
255  result = -EIO;
256  if (fsckPromptUserAction(" initialize directory entry", 1) != 0) {
257  if ((clink = pfsCacheGetData(mount, subpart, number, PFS_CACHE_FLAG_NOLOAD, &result)) != NULL) {
258  pfs_dentry_t *pDentry;
259 
260  memset(clink->u.dentry, 0, pfsMetaSize);
261  pDentry = clink->u.dentry;
262 
263  if (isDir) { // Similar to pfsFillSelfAndParentDentries().
264  // Self entry
265  pDentry->inode = inodeNumber;
266  pDentry->sub = (u8)subpart;
267  pDentry->pLen = 1;
268  pDentry->aLen = FIO_S_IFDIR | 12;
269  pDentry->path[0] = '.';
270  pDentry->path[1] = '\0';
271 
272  // Parent entry
273  pDentry = (pfs_dentry_t *)((u8 *)pDentry + 12);
274 
275  pDentry->inode = inodeNumber;
276  pDentry->sub = (u8)subpart;
277  pDentry->pLen = 2;
278  pDentry->aLen = FIO_S_IFDIR | 500;
279  pDentry->path[0] = '.';
280  pDentry->path[1] = '.';
281  pDentry->path[2] = '\0';
282  } else {
283  pDentry->aLen = sizeof(pfs_dentry_t);
284  }
285 
286  pDentry = clink->u.dentry + 1;
287  pDentry->aLen = sizeof(pfs_dentry_t);
288 
289  clink->flags |= PFS_CACHE_FLAG_DIRTY;
290  pfsCacheFree(clink);
291  }
292  }
293 
294  return result;
295 }
296 
297 // 0x000001c0
298 static int fsckCheckFileBitmap(pfs_mount_t *mount, pfs_blockinfo_t *blockinfo)
299 {
300  pfs_bitmapInfo_t bitmapinfo;
301  pfs_cache_t *clink;
302  u32 chunk, bit, count;
303  u32 *pBitmap;
304 
305  pfsBitmapSetupInfo(mount, &bitmapinfo, blockinfo->subpart, blockinfo->number);
306  for (count = blockinfo->count; count != 0;) {
307  chunk = bitmapinfo.chunk;
308  bitmapinfo.chunk++;
309  // bitmapinfo.index will contain the first index in the bitmap array to start from.
310  if ((clink = pfsBitmapReadPartition(mount, blockinfo->subpart, chunk)) != NULL) { // bitmapinfo.bit will contain the first bit to start checking from.
311  for (pBitmap = &clink->u.bitmap[bitmapinfo.index]; (pBitmap < clink->u.bitmap + 0x100) && count != 0; pBitmap++, bitmapinfo.bit = 0) {
312  for (bit = bitmapinfo.bit; (bit < 32) && (count != 0); bit++, count--) {
313  if ((*pBitmap & (1 << bit)) == 0) {
314  PFS_PRINTF("not marked as used.\n");
315  if (fsckPromptUserAction(" Mark in use", 1) != 0) {
316  *pBitmap |= (1 << bit);
317  clink->flags |= PFS_CACHE_FLAG_DIRTY;
318  } else {
319  return -EINVAL;
320  }
321  }
322  }
323  }
324 
325  bitmapinfo.index = 0;
326  pfsCacheFree(clink);
327  } else {
328  break;
329  }
330  }
331 
332  return 0;
333 }
334 
335 // 0x00005550
336 static int fsckCheckZones(u32 number, u32 size)
337 {
338  u32 index, zone, remaining, bit, startBit;
339  u32 *pZone;
340  pfs_bitmap_t *pBitmap;
341 
342  index = number >> 20;
343  zone = (number >> 5) & 0x7FFF; // Contains the index of the first zone to start checking from.
344  startBit = number & 31;
345  for (remaining = size; remaining != 0;) {
346  pBitmap = pfsBitmapRead(index);
347  index++;
348 
349  if (pBitmap != NULL) { // startBit contains the first bit to start checking from.
350  for (pZone = &pBitmap->bitmap[zone]; (pZone < pBitmap->bitmap + 0x8000) && remaining != 0; pZone++) {
351  for (bit = startBit; bit < 32 && remaining != 0; bit++, remaining--) {
352  if ((*pZone & (1 << bit)) != 0) {
353  PFS_PRINTF("error: overlapped zone found.\n");
354  return 1;
355  }
356 
357  *pZone |= (1 << bit);
358  pBitmap->isDirty = 1;
359  }
360 
361  startBit = 0;
362  }
363 
364  pfsBitmapFree(pBitmap);
365  zone = 0;
366  } else {
367  return -EIO;
368  }
369  }
370 
371  return 0;
372 }
373 
374 // 0x000009dc - BUGBUG - if there's no next segment (blockClink == NULL), this function will end up dereferencing a NULL pointer.
375 static void fsckFillInode(pfs_cache_t *inodeClink, pfs_cache_t *blockClink, u32 blocks, u32 entries, u32 segdesg)
376 {
377  // non-SCE: if NULL, don't do anything
378  if (blockClink == NULL) {
379  return;
380  }
381  memset(&blockClink->u.inode->next_segment, 0, sizeof(blockClink->u.inode->next_segment));
382 
383  inodeClink->u.inode->number_segdesg = (blocks - segdesg) * inodeClink->pfsMount->zsize;
384  inodeClink->u.inode->subpart = 0;
385  if (!FIO_S_ISDIR(inodeClink->u.inode->mode)) {
386  inodeClink->u.inode->attr &= ~PFS_FIO_ATTR_CLOSED;
387  }
388 
389  inodeClink->u.inode->number_blocks = blocks;
390  inodeClink->u.inode->number_data = entries;
391  inodeClink->u.inode->number_segdesg = segdesg;
392  inodeClink->u.inode->last_segment.subpart = blockClink->sub;
393  inodeClink->u.inode->last_segment.number = blockClink->block >> blockClink->pfsMount->inode_scale;
394  blockClink->flags |= PFS_CACHE_FLAG_DIRTY;
395  inodeClink->flags |= PFS_CACHE_FLAG_DIRTY;
396 }
397 
398 // 0x00000b04 - I hate this function and it hates me.
399 static int fsckCheckDirentryInode(pfs_cache_t *direntInodeClink)
400 {
401  int i, result;
402  pfs_cache_t *blockClink, *childDirentBlockClink;
403  pfs_blockinfo_t *pInodeInfo;
404  u32 index, new_index, blocks, segdesg, inodeStart, sector;
405  u32 inodeOffset; // inodeOffset doesn't seem to be 64-bit, even though the inode size field is 64-bits wide.
406 
407  inodeOffset = 0;
408  blocks = 0;
409  segdesg = 1;
410  result = 0;
411  blockClink = pfsCacheUsedAdd(direntInodeClink);
412 
413  // Iterate through the whole directory entry and check that every part of it can be read.
414  for (index = 0; (index < direntInodeClink->u.inode->number_data) && (result == 0); index++) // While within bounds and no error occurs.
415  {
416  new_index = pfsFixIndex(index);
417 
418  if (index != 0 && new_index == 0) { // Read the next inode
419  pInodeInfo = &blockClink->u.inode->next_segment;
420  pfsCacheFree(blockClink);
421  if ((blockClink = pfsCacheGetData(direntInodeClink->pfsMount, pInodeInfo->subpart, pInodeInfo->number << direntInodeClink->pfsMount->inode_scale, PFS_CACHE_FLAG_SEGI, &result)) == NULL) {
422  if ((result == -EIO) && (fsckPromptUserAction(" Remove rest of file", 1) != 0)) {
423  fsckFillInode(direntInodeClink, NULL, blocks, index, segdesg); // bug?! This will cause a NULL-pointer to be dereferenced!
424  }
425  break;
426  }
427 
428  segdesg++;
429  }
430 
431  // 0x00000c18
432  // Check that the block is valid.
433  pInodeInfo = &blockClink->u.inode->data[new_index];
434  if ((direntInodeClink->pfsMount->num_subs < pInodeInfo->subpart) || (pInodeInfo->count == 0) || (pInodeInfo->number < 2) || (ZoneSizes[pInodeInfo->subpart] < ((pInodeInfo->number + pInodeInfo->count) << direntInodeClink->pfsMount->sector_scale))) {
435  putchar('\n');
436  pfsPrintPWD();
437  printf(" contains a bad zone.");
438  if (fsckPromptUserAction(" Remove rest of file", 1) != 0) {
439  fsckFillInode(direntInodeClink, blockClink, blocks, index, segdesg);
440  break;
441  }
442 
443  result = -EINVAL;
444  break;
445  }
446 
447  // 0x00000ccc
448  if (new_index != 0) {
449  if (FIO_S_ISDIR(direntInodeClink->u.inode->mode)) { // If the inode is a directory, then all its blocks contain directory entries. Ensure that all of them can be read.
450  // 0x00000cfc
451  for (i = 0; i < pInodeInfo->count; i++) {
452  inodeStart = (pInodeInfo->number + i) << direntInodeClink->pfsMount->inode_scale;
453 
454  // 0x00000dbc
455  for (sector = 0; (sector < (u32)(1 << direntInodeClink->pfsMount->inode_scale)) && (inodeOffset < direntInodeClink->u.inode->size); sector++) {
456  inodeOffset += pfsMetaSize;
457  if ((childDirentBlockClink = pfsCacheGetData(direntInodeClink->pfsMount, pInodeInfo->subpart, inodeStart + sector, PFS_CACHE_FLAG_NOTHING, &result)) != NULL) {
458  pfsCacheFree(childDirentBlockClink);
459  } else {
460  if (result == -ENOMEM) {
461  goto end;
462  }
463 
464  PFS_PRINTF("could not read directory block.\n");
465  if ((result = pfsInitDirEnt(direntInodeClink->pfsMount, pInodeInfo->subpart, inodeStart + sector, direntInodeClink->u.inode->inode_block.number, (index == 1 && i == 0) ? sector < 1 : 0)) < 0) {
466  goto end2;
467  }
468  }
469  }
470 
471  // 0x00000e0c
472  if (fsckVerbosityLevel >= 10) {
473  putchar('.');
474  }
475  }
476  } else {
477  // The Inode contains a file. Ensure that the whole file can be read.
478  // 0x00000e50
479  for (i = 0; i < pInodeInfo->count; i++) {
480  if (direntInodeClink->pfsMount->blockDev->transfer(direntInodeClink->pfsMount->fd, IOBuffer, pInodeInfo->subpart, (pInodeInfo->number + i) << direntInodeClink->pfsMount->sector_scale, 1 << direntInodeClink->pfsMount->sector_scale, PFS_IO_MODE_READ) == 0) {
481  if (fsckVerbosityLevel >= 10) {
482  putchar('.');
483  }
484 
485  if (fsckRuntimeData.stopFlag != 0) {
486  goto end;
487  }
488  } else {
489  PFS_PRINTF("could not read zone.\n");
490  if (fsckPromptUserAction(" Remove rest of file", 1) != 0) {
491  fsckFillInode(direntInodeClink, blockClink, blocks, index, segdesg);
492  }
493 
494  goto end;
495  }
496  }
497  }
498  }
499 
500  // 0x00000ef8
501  // Check the free space bitmap.
502  if ((result = fsckCheckFileBitmap(direntInodeClink->pfsMount, pInodeInfo)) >= 0) {
503  result = fsckCheckZones(pInodeInfo->number + ZoneMap[pInodeInfo->subpart], pInodeInfo->count);
504  if (result > 0) { // 0x00000f44
505  if (fsckPromptUserAction(" Remove rest of file", 1) != 0) {
506  fsckFillInode(direntInodeClink, blockClink, blocks, index, segdesg);
507  }
508  break;
509  } else if (result < 0) // result < 0
510  {
511  goto end2;
512  }
513  } else
514  goto end2;
515 
516  // 0x00000f7c - Final part of the loop.
517  fsckRuntimeData.status.inodeBlockCount += pInodeInfo->count;
518  blocks += pInodeInfo->count;
519  if (fsckRuntimeData.stopFlag != 0)
520  break;
521  }
522 
523 end:
524  if (result < 0) {
525  end2:
526  fsckRuntimeData.hasError = 1;
527  }
528 
529  // 0x00000ff0
530  if (fsckVerbosityLevel >= 2)
531  printf("\n");
532 
533  pfsCacheFree(blockClink);
534 
535  return result;
536 }
537 
538 // 0x00000828
539 static void fsckFixDEntry(pfs_cache_t *clink, pfs_dentry_t *dentry)
540 {
541  u32 dEntrySize, offset;
542  u16 aLen;
543  pfs_dentry_t *pDEntryNew, *pDEntry;
544 
545  dEntrySize = (u32)((u8 *)dentry - (u8 *)clink->u.dentry);
546  // if((s32)dEntrySize < 0)
547  if (clink->u.dentry > dentry)
548  dEntrySize += 0x1FF;
549 
550  dEntrySize = dEntrySize >> 9 << 9; // Round off
551  pDEntryNew = (pfs_dentry_t *)((u8 *)clink->u.dentry + dEntrySize);
552  for (pDEntry = NULL, offset = 0; offset < sizeof(pfs_dentry_t); offset += aLen, pDEntry = pDEntryNew, pDEntryNew = (pfs_dentry_t *)((u8 *)pDEntryNew + aLen)) {
553  aLen = pDEntryNew->aLen & 0x0FFF;
554 
555  if (pDEntryNew == dentry) {
556  if (pDEntry != NULL) {
557  pDEntry->aLen = (pDEntry->aLen & FIO_S_IFMT) | ((pDEntry->aLen & 0x0FFF) + aLen);
558  } else {
559  pDEntryNew->inode = 0;
560  pDEntryNew->pLen = 0;
561  }
562 
563  clink->flags |= PFS_CACHE_FLAG_DIRTY;
564  break;
565  }
566  }
567 }
568 
569 // 0x000012b4
570 static void fsckCheckSelfEntry(pfs_cache_t *SelfInodeClink, pfs_cache_t *SelfDEntryClink, pfs_dentry_t *dentry)
571 {
572  if ((SelfInodeClink->sub != dentry->sub) || (SelfInodeClink->u.inode->inode_block.number != dentry->inode)) {
573  PFS_PRINTF("'.' point not itself.\n");
574  if (fsckPromptUserAction(" Fix", 1) != 0) {
575  dentry->sub = SelfInodeClink->u.inode->inode_block.subpart;
576  dentry->inode = SelfInodeClink->u.inode->inode_block.number;
577  SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
578  }
579  }
580 }
581 
582 // 0x00001374
583 static void fsckCheckParentEntry(pfs_cache_t *ParentInodeClink, pfs_cache_t *SelfDEntryClink, pfs_dentry_t *dentry)
584 {
585  if ((ParentInodeClink->sub != dentry->sub) || (ParentInodeClink->u.inode->inode_block.number != dentry->inode)) {
586  PFS_PRINTF("'..' point not parent.\n");
587  if (fsckPromptUserAction(" Fix", 1) != 0) {
588  dentry->sub = ParentInodeClink->u.inode->inode_block.subpart;
589  dentry->inode = ParentInodeClink->u.inode->inode_block.number;
590  SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
591  }
592  }
593 }
594 
595 static void fsckCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink);
596 
597 // 0x00001054
598 static void fsckCheckFile(pfs_cache_t *FileInodeClink, pfs_cache_t *FileInodeDataClink, pfs_dentry_t *dentry)
599 {
600  if (fsckRuntimeData.status.PWDLevel < FSCK_MAX_PATH_LEVELS - 1) {
601  memset(fsckPathBuffer[fsckRuntimeData.status.PWDLevel], 0, FSCK_MAX_PATH_SEG_LENGTH);
602  strncpy(fsckPathBuffer[fsckRuntimeData.status.PWDLevel], dentry->path, dentry->pLen);
603  fsckRuntimeData.status.PWDLevel++;
604 
605  if (fsckVerbosityLevel >= 2) {
606  pfsPrintPWD();
607  if (FIO_S_ISDIR(dentry->aLen)) {
608  printf(": ");
609  }
610  }
611 
612  if (FIO_S_ISREG(dentry->aLen)) {
613  if (FileInodeDataClink->pfsMount->blockDev->transfer(FileInodeDataClink->pfsMount->fd, IOBuffer, FileInodeDataClink->sub, (FileInodeDataClink->block + 1) << pfsBlockSize, 1 << pfsBlockSize, PFS_IO_MODE_READ) != 0) {
614  PFS_PRINTF("could not read extended attribute.\n");
615  if (fsckPromptUserAction(" initialize attribute", 1) != 0) {
616  memset(IOBuffer, 0, 1024);
617  ((pfs_aentry_t *)IOBuffer)->aLen = 1024;
618  if (FileInodeDataClink->pfsMount->blockDev->transfer(FileInodeDataClink->pfsMount->fd, IOBuffer, FileInodeDataClink->sub, (FileInodeDataClink->block + 1) << pfsBlockSize, 1 << pfsBlockSize, PFS_IO_MODE_WRITE) != 0) {
619  fsckRuntimeData.hasError = 1;
620  }
621  } else // This is not actually needed, but it's done in the original.
622  {
623  fsckRuntimeData.hasError = 1;
624  }
625  }
626  }
627 
628  // 0x00001220
629  fsckCheckDirentryInode(FileInodeDataClink);
630  if (FIO_S_ISDIR(dentry->aLen)) {
631  fsckRuntimeData.status.directories++;
632  fsckCheckFiles(FileInodeClink, FileInodeDataClink);
633  } else {
634  fsckRuntimeData.status.files++;
635  }
636 
637  fsckRuntimeData.status.PWDLevel--;
638  } else {
639  PFS_PRINTF("error: exceed max directory depth.\n");
640  fsckRuntimeData.hasError = 1;
641  }
642 }
643 
644 // 0x00001434
645 static void fsckCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink)
646 {
647  pfs_blockpos_t BlockPosition;
648  pfs_dentry_t *pDEntry, *pDEntryEnd;
649  int result;
650  u32 inodeOffset, dEntrySize; // inodeOffset doesn't seem to be 64-bit, even though the inode size field is 64-bits wide.
651  pfs_cache_t *DEntryClink, *FileInodeDataClink;
652 
653  inodeOffset = 0;
654  BlockPosition.inode = pfsCacheUsedAdd(InodeClink);
655  BlockPosition.block_segment = 1;
656  BlockPosition.block_offset = 0;
657  BlockPosition.byte_offset = 0;
658  if ((DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
659  pfsCacheFree(BlockPosition.inode);
660  fsckRuntimeData.hasError = 1;
661  return;
662  }
663  pDEntry = DEntryClink->u.dentry;
664 
665  // 0x000017c0
666  while (inodeOffset < InodeClink->u.inode->size) {
667  // 0x000014cc
668  if (pDEntry >= (pfs_dentry_t *)(DEntryClink->u.data + 1024)) {
669  // Read next inode
670  // 0x000014e4
671  pfsCacheFree(DEntryClink);
672  if (pfsInodeSync(&BlockPosition, 1024, InodeClink->u.inode->number_data) != 0 || (DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
673  fsckRuntimeData.hasError = 1;
674  goto end;
675  }
676 
677  pDEntry = DEntryClink->u.dentry;
678  }
679 
680  // 0x0000153c
681  for (pDEntryEnd = pDEntry + 1; pDEntry < pDEntryEnd; pDEntry = (pfs_dentry_t *)((u8 *)pDEntry + dEntrySize), inodeOffset += dEntrySize) {
682  if (fsckRuntimeData.stopFlag != 0) {
683  goto end;
684  }
685 
686  dEntrySize = pDEntry->aLen & 0x0FFF;
687 
688  if (dEntrySize & 3) {
689  dEntrySize = (u32)((u8 *)pDEntryEnd - (u8 *)pDEntry);
690  PFS_PRINTF("directory entry is not aligned.\n");
691 
692  if (fsckPromptUserAction(" Fix", 1) != 0) {
693  pDEntry->aLen = (pDEntry->aLen & 0xF000) | dEntrySize;
694  DEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
695  }
696  }
697 
698  if (dEntrySize < (u32)((pDEntry->pLen + 11) & ~3)) {
699  dEntrySize = (u32)((u8 *)pDEntryEnd - (u8 *)pDEntry);
700  PFS_PRINTF("directory entry is too small.\n");
701 
702  if (fsckPromptUserAction(" Fix", 1) != 0) {
703  if ((u32)((pDEntry->pLen + 11) & ~3) < dEntrySize) {
704  pDEntry->aLen = (pDEntry->aLen & 0xF000) | dEntrySize;
705  DEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
706  } else {
707  fsckFixDEntry(DEntryClink, pDEntry);
708  pDEntry->inode = 0;
709  }
710  } else {
711  pDEntry->inode = 0;
712  }
713  }
714 
715  // 0x00001654
716  if (pDEntryEnd < (pfs_dentry_t *)((u8 *)pDEntry + dEntrySize)) {
717  dEntrySize = (u32)((u8 *)pDEntryEnd - (u8 *)pDEntry);
718  PFS_PRINTF("directory entry is too long.\n");
719  if (fsckPromptUserAction(" Fix", 1) != 0) {
720  fsckFixDEntry(DEntryClink, pDEntry);
721  }
722 
723  pDEntry->inode = 0;
724  }
725 
726  // 0x00001694
727  if (pDEntry->inode != 0) {
728  if ((pDEntry->pLen == 1) && (pDEntry->path[0] == '.')) {
729  fsckCheckSelfEntry(InodeClink, DEntryClink, pDEntry);
730  } else if ((pDEntry->pLen == 2) && (pDEntry->path[0] == '.')) {
731  fsckCheckParentEntry(ParentInodeClink, DEntryClink, pDEntry);
732  } else {
733  if ((FileInodeDataClink = pfsInodeGetData(InodeClink->pfsMount, pDEntry->sub, pDEntry->inode, &result)) != NULL) {
734  fsckCheckFile(InodeClink, FileInodeDataClink, pDEntry);
735  pfsCacheFree(FileInodeDataClink);
736  } else {
737  if (result == -EIO) {
738  printf(" contains an unreadable file '%.*s'.\n", pDEntry->pLen, pDEntry->path);
739  if (fsckPromptUserAction(" Remove", 1) != 0)
740  fsckFixDEntry(DEntryClink, pDEntry);
741  } else
742  fsckRuntimeData.hasError = 1;
743  }
744  }
745  }
746  }
747 
748  // 0x000017ac
749  if (fsckRuntimeData.stopFlag != 0)
750  break;
751  }
752 
753 end:
754  pfsCacheFree(DEntryClink);
755  pfsCacheFree(BlockPosition.inode);
756 }
757 
758 // 0x0000054c
759 static void fsckCompareBitmap(pfs_mount_t *mount, void *buffer)
760 {
761  int hasUpdate;
762  u32 i, NumZones, zone;
763  u32 *pBitmap, ZoneStartOffset, *pRawBitmap, RawSize, unaligned, length, offset;
764 
765  (void)buffer;
766 
767  for (i = 0, offset = 0; i < mount->num_subs + 1; i++, offset++) {
768  RawSize = ZoneSizes[i] >> mount->sector_scale;
769  NumZones = RawSize / (mount->zsize << 3);
770  unaligned = RawSize % (mount->zsize << 3);
771 
772  for (zone = 0; (unaligned == 0 && zone < NumZones) || (unaligned != 0 && zone < NumZones + 1); zone++) {
773  length = (zone == NumZones) ? unaligned : mount->zsize << 3;
774  hasUpdate = 0;
775 
776  pBitmap = pfsGetBitmapEntry(offset + (zone * (mount->zsize << 3)));
777  ZoneStartOffset = (i == 0) ? (0x2000 >> mount->sector_scale) + 1 : 1;
778  if (mount->blockDev->transfer(mount->fd, IOBuffer, i, (ZoneStartOffset + zone) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ) < 0) {
779  break;
780  }
781 
782  for (pRawBitmap = (u32 *)IOBuffer; pRawBitmap < (u32 *)(IOBuffer + (length >> 3)); pRawBitmap++, pBitmap++) {
783  // 0x00000698
784  if (*pRawBitmap != *pBitmap) {
785  PFS_PRINTF("bitmap unmatch %08lx, %08lx\n", *pRawBitmap, *pBitmap);
786 #ifdef FSCK100
787  if (fsckPromptUserAction(" Replace", 1) != 0)
788 #else
789  if (fsckPromptUserAction2(" Replace", 1) != 0)
790 #endif
791  {
792  *pRawBitmap = *pBitmap;
793  hasUpdate = 1;
794  }
795  }
796  }
797 
798  if (hasUpdate != 0) {
799  mount->blockDev->transfer(mount->fd, IOBuffer, i, (ZoneStartOffset + zone) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_WRITE);
800  }
801  }
802  }
803 }
804 
805 // 0x00001f34
806 static void FsckThread(void *arg)
807 {
808  pfs_cache_t *clink;
809  pfs_mount_t *mount = (pfs_mount_t *)arg;
810  pfs_super_block_t *super = (pfs_super_block_t *)IOBuffer;
811 
812 #ifdef FSCK100
813  if (fsckVerbosityLevel > 0) {
814  PFS_PRINTF("Check Root Directory...\n");
815  }
816 #else
817  if (fsckVerbosityLevel > 0) {
818  PFS_PRINTF("Check Extended attribute...\n");
819  }
820 
821  if (fsckCheckExtendedAttribute(mount) < 0) {
822  PFS_PRINTF("error: I cannot continue, giving up.\n");
823  goto fsck_thread_end;
824  }
825 
826  if (fsckVerbosityLevel > 0) {
827  PFS_PRINTF("done.\n");
828 
829  PFS_PRINTF("Check Root Directory...\n");
830  }
831 #endif
832 
833  if ((clink = CheckRootDirectory(mount)) == NULL) {
834  PFS_PRINTF("error: I cannot continue, giving up.\n");
835  goto fsck_thread_end;
836  }
837 
838  fsckRuntimeData.status.directories++;
839 
840  if (fsckVerbosityLevel > 0)
841  PFS_PRINTF("done.\n");
842 
843  if (fsckVerbosityLevel > 0)
844  PFS_PRINTF("Check all files...\n");
845 
846  fsckCheckFiles(clink, clink);
847 
848  if (fsckVerbosityLevel > 0)
849  PFS_PRINTF("done.\n");
850 
851  pfsCacheFlushAllDirty(mount);
852  pfsCacheFree(clink);
853 
854  // 0x00002030
855  if (fsckRuntimeData.hasError == 0) {
856  if (fsckRuntimeData.stopFlag == 0) {
857  if (fsckVerbosityLevel > 0) {
858  PFS_PRINTF("Compare bitmap...\n");
859  }
860 
861  fsckCompareBitmap(mount, IOBuffer);
862 
863  if (fsckVerbosityLevel > 0) {
864  PFS_PRINTF("done.\n");
865  }
866  }
867 
868  // 0x000020ac
869  if (fsckRuntimeData.hasError == 0) {
870  if (fsckRuntimeData.stopFlag == 0) { // Clear the write error state, if it was set.
871  if (mount->blockDev->transfer(mount->fd, super, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ) == 0) {
872  if (super->pfsFsckStat & PFS_FSCK_STAT_WRITE_ERROR) {
873  super->pfsFsckStat &= ~PFS_FSCK_STAT_WRITE_ERROR;
874  mount->blockDev->transfer(mount->fd, super, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
875  }
876  }
877 
878  iomanX_ioctl2(mount->fd, HIOCGETPARTERROR, NULL, 0, NULL, 0);
879  }
880  }
881  }
882 
883  // 0x00002164
884  if (fsckRuntimeData.status.fixedErrorCount != 0) { // Indicate that errors were fixed.
885  if (mount->blockDev->transfer(mount->fd, super, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ) == 0) {
886  super->pfsFsckStat |= PFS_FSCK_STAT_ERRORS_FIXED;
887  mount->blockDev->transfer(mount->fd, super, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
888  }
889  }
890 
891  mount->blockDev->flushCache(mount->fd);
892 
893 fsck_thread_end:
894  SetEventFlag(fsckEventFlagID, 1);
895 }
896 
897 // 0x00000340
898 static int fsckCheckBitmap(pfs_mount_t *mount, void *buffer)
899 {
900  u32 i, count, block, BitmapStart, sector;
901  int result;
902 
903  result = 0;
904  for (i = 0; i < mount->num_subs + 1; i++) {
905  block = 0;
906  for (block = 0, count = pfsGetBitmapSizeBlocks(mount->sector_scale, ZoneSizes[i]); block < count; block++) {
907  BitmapStart = block + 1;
908  if (i == 0) {
909  BitmapStart += 0x2000 >> mount->sector_scale;
910  }
911 
912  if ((result = mount->blockDev->transfer(mount->fd, buffer, i, BitmapStart << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ)) < 0) {
913  PFS_PRINTF("cannot read bitmap\n");
914  if (fsckPromptUserAction(" Overwrite", 1) == 0) {
915  return result;
916  }
917 
918  for (sector = 0, result = 0; sector < (u32)(1 << mount->sector_scale); sector++) {
919  // 0x0000044c
920  if (mount->blockDev->transfer(mount->fd, buffer, i, (BitmapStart << mount->sector_scale) + sector, 1, PFS_IO_MODE_READ) < 0) {
921  memset(buffer, -1, 512);
922  if ((result = mount->blockDev->transfer(mount->fd, buffer, i, (BitmapStart << mount->sector_scale) + sector, 1, PFS_IO_MODE_WRITE)) < 0) {
923  PFS_PRINTF("error: overwrite bitmap failed.\n");
924  return result;
925  }
926  }
927  }
928  }
929  }
930  }
931 
932  return result;
933 }
934 
935 // 0x000018b8
936 static int CheckSuperBlock(pfs_mount_t *pMainPFSMount)
937 {
938  int result, i;
939  pfs_super_block_t *super = (pfs_super_block_t *)IOBuffer;
940 
941  pMainPFSMount->num_subs = pMainPFSMount->blockDev->getSubNumber(pMainPFSMount->fd);
942  if (pMainPFSMount->blockDev->transfer(pMainPFSMount->fd, super, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ) < 0 || (super->magic != PFS_SUPER_MAGIC)) {
943  // 0x00001930
944  PFS_PRINTF("Read super block failed, try another.\n");
945 
946  if (pMainPFSMount->blockDev->transfer(pMainPFSMount->fd, IOBuffer, 0, PFS_SUPER_BACKUP_SECTOR, 1, PFS_IO_MODE_READ) != 0) {
947  PFS_PRINTF("error: could not read any super block.\n");
948  return -EIO;
949  }
950 
951  result = (super->magic == PFS_SUPER_MAGIC) ? 0 : -EIO;
952 
953  if (result != 0) {
954  PFS_PRINTF("error: could not read any super block.\n");
955  return -EIO;
956  }
957 
958  if (fsckPromptUserAction(" Overwrite super block", 1) == 0) {
959  return -EIO;
960  }
961 
962  if ((result = pMainPFSMount->blockDev->transfer(pMainPFSMount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE)) < 0) {
963  PFS_PRINTF("error: overwrite failed.\n");
964  return result;
965  }
966  }
967 
968  // 0x00001a1c
969  if (super->version > PFS_FORMAT_VERSION) {
970  PFS_PRINTF("error: unknown version.\n");
971  return -EINVAL;
972  }
973 
974  if (((super->zone_size & (super->zone_size - 1)) != 0) ||
975  (super->zone_size < 0x800) ||
976  (0x20000 < super->zone_size)) {
977  PFS_PRINTF("error: invalid zone size.\n");
978  return -EINVAL;
979  }
980 
981  if (pMainPFSMount->num_subs < super->num_subs) {
982  PFS_PRINTF("filesystem larger than partition size.\n");
983 
984  if (fsckPromptUserAction(" Fix size", 1) == 0) {
985  return -EINVAL;
986  }
987 
988  super->num_subs = pMainPFSMount->num_subs;
989  if ((result = pMainPFSMount->blockDev->transfer(pMainPFSMount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE)) < 0) {
990  PFS_PRINTF("error: could not fix the filesystem size.\n");
991  return result;
992  }
993  }
994 
995  pMainPFSMount->zsize = super->zone_size;
996  pMainPFSMount->sector_scale = pfsGetScale(super->zone_size, 512);
997  pMainPFSMount->inode_scale = pfsGetScale(super->zone_size, 1024);
998 
999  memcpy(&pMainPFSMount->root_dir, &super->root, sizeof(pMainPFSMount->root_dir));
1000  memcpy(&pMainPFSMount->log, &super->log, sizeof(pMainPFSMount->log));
1001  memcpy(&pMainPFSMount->current_dir, &super->root, sizeof(pMainPFSMount->current_dir));
1002  pMainPFSMount->total_zones = 0;
1003 
1004  if (fsckVerbosityLevel) {
1005  PFS_PRINTF("\tlog check...\n");
1006  }
1007 
1008  if ((result = pfsJournalRestore(pMainPFSMount)) < 0)
1009  return result;
1010 
1011  memset(ZoneSizes, 0, 0x10);
1012  memset(ZoneMap, 0, 0x10);
1013 
1014  for (i = 0; (u32)i < pMainPFSMount->num_subs + 1; i++) {
1015  ZoneSizes[i] = pMainPFSMount->blockDev->getSize(pMainPFSMount->fd, i);
1016  if (i != 0) {
1017  ZoneMap[i] = (ZoneSizes[i - 1] >> pMainPFSMount->sector_scale) + ZoneMap[i - 1];
1018  }
1019  }
1020 
1021  if (fsckVerbosityLevel > 0) {
1022  PFS_PRINTF("\tCheck Bitmaps...\n");
1023  }
1024 
1025  // 0x00001c80
1026  if ((result = fsckCheckBitmap(pMainPFSMount, IOBuffer)) >= 0) {
1027  u32 *pFreeZones;
1028 
1029  if (fsckVerbosityLevel > 0) {
1030  PFS_PRINTF("\tdone.\n");
1031  }
1032 
1033  for (i = 0, pFreeZones = pMainPFSMount->free_zone; (u32)i < pMainPFSMount->num_subs + 1; i++, pFreeZones++) {
1034  pMainPFSMount->total_zones += ZoneSizes[i] >> pMainPFSMount->sector_scale;
1035  pMainPFSMount->zfree += (*pFreeZones = pfsBitmapCalcFreeZones(pMainPFSMount, i));
1036  }
1037 
1038  if (fsckVerbosityLevel > 0) {
1039  PFS_PRINTF("zonesz %ld, %ld zones, %ld free.\n", pMainPFSMount->zsize, pMainPFSMount->total_zones, pMainPFSMount->zfree);
1040  }
1041  }
1042 
1043  return result;
1044 }
1045 
1046 // 0x00002224
1047 static int FsckOpen(iomanX_iop_file_t *fd, const char *name, int flags, int mode)
1048 {
1049  int blockfd, result;
1050  u32 count;
1051  iox_stat_t StatData;
1052  pfs_block_device_t *pblockDevData;
1053 
1054  (void)flags;
1055 
1056  fsckWriteEnabled = mode & FSCK_MODE_WRITE;
1057  fsckAutoMode = mode & FSCK_MODE_AUTO;
1058  fsckVerbosityLevel = (mode & 0xF0) >> 4;
1059 
1060  if (MainPFSMount.fd) {
1061  return -EBUSY;
1062  }
1063 
1064  if ((result = iomanX_getstat(name, &StatData)) < 0) {
1065  PFS_PRINTF("error: could not get status.\n");
1066  return result;
1067  }
1068 
1069  if (StatData.mode != APA_TYPE_PFS) {
1070  PFS_PRINTF("error: not PFS.\n");
1071  return -EINVAL;
1072  }
1073 
1074  if ((pblockDevData = pfsGetBlockDeviceTable(name)) == NULL) {
1075  return -ENXIO;
1076  }
1077 
1078  if ((blockfd = iomanX_open(name, O_RDWR)) < 0) {
1079  PFS_PRINTF("error: cannot open.\n");
1080  return blockfd;
1081  }
1082 
1083  memset(&MainPFSMount, 0, sizeof(MainPFSMount));
1084  MainPFSMount.fd = blockfd;
1085  MainPFSMount.blockDev = pblockDevData;
1086 
1087  if (fsckVerbosityLevel > 0) {
1088  PFS_PRINTF("Check Super Block...\n");
1089  }
1090 
1091  if ((result = CheckSuperBlock(&MainPFSMount)) < 0) {
1092  MainPFSMount.fd = 0;
1093  PFS_PRINTF("error: cannot continue.\n");
1094  return result;
1095  }
1096 
1097  if (fsckVerbosityLevel > 0) {
1098  PFS_PRINTF("done.\n");
1099  }
1100 
1101  if ((result = pfsBitmapPartInit(MainPFSMount.total_zones)) >= 0) {
1102  int i;
1103 
1104  // 0x000023bc
1105  memset(&fsckRuntimeData, 0, sizeof(fsckRuntimeData));
1106 
1107  fsckRuntimeData.status.zoneUsed = MainPFSMount.total_zones - MainPFSMount.zfree;
1108  for (i = 0; (u32)i < MainPFSMount.num_subs + 1; fsckRuntimeData.status.inodeBlockCount += count, i++) {
1109  count = pfsGetBitmapSizeBlocks(MainPFSMount.sector_scale, ZoneSizes[i]) + 1;
1110  if (i == 0) {
1111  count += (0x2000 >> MainPFSMount.sector_scale) + MainPFSMount.log.count;
1112  }
1113 
1114  if (fsckCheckZones(ZoneMap[i], count) < 0) {
1115  break;
1116  }
1117  }
1118 
1119  // 0x0000246c
1120  fd->privdata = &MainPFSMount;
1121  result = 0;
1122  } else {
1123  MainPFSMount.fd = 0;
1124  }
1125 
1126  return result;
1127 }
1128 
1129 // 0x000024a4
1130 static int FsckClose(iomanX_iop_file_t *fd)
1131 {
1132  iomanX_close(((pfs_mount_t *)fd->privdata)->fd);
1133  pfsCacheClose((pfs_mount_t *)fd->privdata);
1134  memset(fd->privdata, 0, sizeof(pfs_mount_t));
1135 
1136  return 0;
1137 }
1138 
1139 // 0x00001d7c
1140 static int fsckGetEstimatedTime(pfs_mount_t *mount, int *result)
1141 {
1142  unsigned int i;
1143  u64 clock;
1144  iop_sys_clock_t SysClock1, SysClock2, SysClockDiff;
1145  u32 sec, usec;
1146 
1147  clock = 1000000;
1148  for (i = 0; i < 4; i++) {
1149  GetSystemTime(&SysClock1);
1150  mount->blockDev->transfer(mount->fd, IOBuffer, 0, 1 << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ);
1151  GetSystemTime(&SysClock2);
1152 
1153  SysClockDiff.lo = SysClock2.lo - SysClock1.lo;
1154  SysClockDiff.hi = SysClock2.hi - SysClock1.hi - (SysClock2.lo < SysClock1.lo);
1155  SysClock2USec(&SysClockDiff, &sec, &usec);
1156 
1157  PFS_PRINTF("%ld system clocks = %ld.%06ld sec\n", SysClockDiff.lo, sec, usec);
1158 
1159  if (usec < clock) {
1160  clock = usec;
1161  }
1162  }
1163 
1164  // 0x00001e8c
1165  if ((*result = ((clock + 400) * fsckRuntimeData.status.zoneUsed / 1000000)) == 0) {
1166  *result = 1;
1167  }
1168 
1169  return 0;
1170 }
1171 
1172 // 0x000024f0
1173 static int FsckIoctl2(iomanX_iop_file_t *fd, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
1174 {
1175  int result;
1176  u32 FlagBits;
1177 
1178  (void)arg;
1179  (void)arglen;
1180  (void)buflen;
1181 
1182  switch (cmd) {
1183  case FSCK_IOCTL2_CMD_GET_ESTIMATE: // 0x00002528
1184  result = fsckGetEstimatedTime(fd->privdata, buf);
1185  break;
1186  case FSCK_IOCTL2_CMD_START: // 0x0000253c
1187  result = StartThread(fsckThreadID, fd->privdata);
1188  break;
1189  case FSCK_IOCTL2_CMD_WAIT: // 0x00002554
1190  result = WaitEventFlag(fsckEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
1191  break;
1192  case FSCK_IOCTL2_CMD_POLL: // 0x00002574
1193  result = PollEventFlag(fsckEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
1194  if (result == KE_EVF_COND) {
1195  result = 1;
1196  }
1197  break;
1198  case FSCK_IOCTL2_CMD_GET_STATUS: // 0x000025a8
1199  memcpy(buf, &fsckRuntimeData.status, sizeof(struct fsckStatus));
1200  result = 0;
1201  break;
1202  case FSCK_IOCTL2_CMD_STOP: // 0x0000262c
1203  fsckRuntimeData.stopFlag = 1;
1204  result = 0;
1205  break;
1206  default:
1207  result = 0;
1208  }
1209 
1210  return result;
1211 }
1212 
1213 IOMANX_RETURN_VALUE_IMPL(0);
1214 
1215 static iomanX_iop_device_ops_t FsckDeviceOps = {
1216  IOMANX_RETURN_VALUE(0), // init
1217  IOMANX_RETURN_VALUE(0), // deinit
1218  IOMANX_RETURN_VALUE(0), // format
1219  &FsckOpen, // open
1220  &FsckClose, // close
1221  IOMANX_RETURN_VALUE(0), // read
1222  IOMANX_RETURN_VALUE(0), // write
1223  IOMANX_RETURN_VALUE(0), // lseek
1224  IOMANX_RETURN_VALUE(0), // ioctl
1225  IOMANX_RETURN_VALUE(0), // remove
1226  IOMANX_RETURN_VALUE(0), // mkdir
1227  IOMANX_RETURN_VALUE(0), // rmdir
1228  IOMANX_RETURN_VALUE(0), // dopen
1229  IOMANX_RETURN_VALUE(0), // dclose
1230  IOMANX_RETURN_VALUE(0), // dread
1231  IOMANX_RETURN_VALUE(0), // getstat
1232  IOMANX_RETURN_VALUE(0), // chstat
1233  IOMANX_RETURN_VALUE(0), // rename
1234  IOMANX_RETURN_VALUE(0), // chdir
1235  IOMANX_RETURN_VALUE(0), // sync
1236  IOMANX_RETURN_VALUE(0), // mount
1237  IOMANX_RETURN_VALUE(0), // umount
1238  IOMANX_RETURN_VALUE_S64(0), // lseek64
1239  IOMANX_RETURN_VALUE(0), // devctl
1240  IOMANX_RETURN_VALUE(0), // symlink
1241  IOMANX_RETURN_VALUE(0), // readlink
1242  &FsckIoctl2, // ioctl2
1243 };
1244 
1245 static iomanX_iop_device_t FsckDevice = {
1246  "fsck",
1247  IOP_DT_FSEXT | IOP_DT_FS,
1248  1,
1249  "FSCK",
1250  &FsckDeviceOps};
1251 
1252 // 0x0000267c
1253 int PFS_ENTRYPOINT(int argc, char **argv)
1254 {
1255  int buffers;
1256 
1257  buffers = 0x7E;
1258  for (argc--, argv++; argc > 0 && ((*argv)[0] == '-'); argc--, argv++) {
1259  if (!strcmp("-n", *argv)) {
1260  argv++;
1261  if (--argc > 0) {
1262  if (strtol(*argv, NULL, 10) < buffers) {
1263  buffers = strtol(*argv, NULL, 10);
1264  }
1265  } else {
1266  return DisplayUsageHelp();
1267  }
1268  } else {
1269  return DisplayUsageHelp();
1270  }
1271  }
1272 
1273  PFS_PRINTF("max depth %d, %d buffers.\n", FSCK_MAX_PATH_LEVELS - 1, buffers);
1274 
1275  if (pfsCacheInit(buffers, 1024) < 0) {
1276  PFS_PRINTF("error: cache initialization failed.\n");
1277  return MODULE_NO_RESIDENT_END;
1278  }
1279 
1280  if (pfsBitmapInit() < 0) {
1281  PFS_PRINTF("error: bitmap initialization failed.\n");
1282  return MODULE_NO_RESIDENT_END;
1283  }
1284 
1285  if ((fsckEventFlagID = fsckCreateEventFlag()) < 0) {
1286  return MODULE_NO_RESIDENT_END;
1287  }
1288 
1289  if ((fsckThreadID = fsckCreateThread(&FsckThread, 0x2080)) < 0) {
1290  return MODULE_NO_RESIDENT_END;
1291  }
1292 
1293  iomanX_DelDrv(FsckDevice.name);
1294  if (iomanX_AddDrv(&FsckDevice) == 0) {
1295  PFS_PRINTF("version %04x driver start.\n", IRX_VER(PFS_MAJOR, PFS_MINOR));
1296  return MODULE_RESIDENT_END;
1297  }
1298 
1299  return MODULE_NO_RESIDENT_END;
1300 }
iomanX.h
iox_stat_t
Definition: iox_stat.h:92
pfs_cache_s
Definition: libpfs.h:195
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
FIO_S_IFDIR
#define FIO_S_IFDIR
Definition: iox_stat.h:45
thbase.h
_iomanX_iop_file
Definition: iomanX.h:70
fsckRuntimeData
Definition: fsck.c:32
sysclib.h
ENOMEM
#define ENOMEM
Definition: errno.h:43
ENXIO
#define ENXIO
Definition: errno.h:31
EIO
#define EIO
Definition: errno.h:29
loadcore.h
pfs_super_block_t
Definition: libpfs.h:134
pfs_blockinfo_t
Definition: libpfs.h:116
fsckStatus
Definition: fsck-ioctl.h:14
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
hdd-ioctl.h
pfs_block_device_t
Definition: libpfs.h:169
irx.h
_iomanX_iop_device_ops
Definition: iomanX.h:95
EBUSY
#define EBUSY
Definition: errno.h:51
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
FIO_S_IFMT
#define FIO_S_IFMT
Definition: iox_stat.h:39
pfs_blockpos_t
Definition: libpfs.h:213
pfs_mount_t
Definition: libpfs.h:178
EINVAL
#define EINVAL
Definition: errno.h:63
HIOCGETPARTERROR
#define HIOCGETPARTERROR
Definition: hdd-ioctl.h:69
pfs_bitmapInfo_t
Definition: libpfs.h:262
thevent.h
_iop_sys_clock
Definition: thbase.h:87
pfs_bitmap
Definition: bitmap_fsck.h:14
errno.h
kerr.h
pfs_aentry_t
Definition: libpfs.h:99
pfs_dentry_t
Definition: libpfs.h:107