PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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
29IRX_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
39static int fsckWriteEnabled;
40static int fsckAutoMode;
41static int fsckVerbosityLevel;
42extern u32 pfsMetaSize;
43extern u32 pfsBlockSize;
44static 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
50static 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
56static int fsckEventFlagID;
57static int fsckThreadID;
58static char fsckPathBuffer[FSCK_MAX_PATH_LEVELS][FSCK_MAX_PATH_SEG_LENGTH];
59
60static u32 ZoneSizes[0x41]; // Contains the sizes of all zones, in units of 512-byte sectors.
61static u32 ZoneMap[0x41]; // Contains the starting addresses of all zones, in units of blocks.
62
63// 0x00000000
64const 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
89static 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
131static 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
169static int DisplayUsageHelp(void)
170{
171 PFS_PRINTF("error: Usage: fsck [-n <num>]\n");
172 return MODULE_NO_RESIDENT_END;
173}
174
175#ifndef FSCK100
176static 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
209static int fsckCheckDirentryInode(pfs_cache_t *clink);
210
211// 0x0000183c
212static 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
235static 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
250static 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
298static 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
336static 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.
375static 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.
399static 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
523end:
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
539static 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
570static 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
583static 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
595static void fsckCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink);
596
597// 0x00001054
598static 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
645static 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
753end:
754 pfsCacheFree(DEntryClink);
755 pfsCacheFree(BlockPosition.inode);
756}
757
758// 0x0000054c
759static 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
806static 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
893fsck_thread_end:
894 SetEventFlag(fsckEventFlagID, 1);
895}
896
897// 0x00000340
898static 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
936static 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
1047static 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
1130static 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
1140static 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
1173static 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
1213IOMANX_RETURN_VALUE_IMPL(0);
1214
1215static 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
1245static iomanX_iop_device_t FsckDevice = {
1246 "fsck",
1247 IOP_DT_FSEXT | IOP_DT_FS,
1248 1,
1249 "FSCK",
1250 &FsckDeviceOps};
1251
1252// 0x0000267c
1253int 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}
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define ENOMEM
Definition errno.h:43
#define EIO
Definition errno.h:29
#define EBUSY
Definition errno.h:51
#define HIOCGETPARTERROR
Definition hdd-ioctl.h:69
#define IOP_DT_FSEXT
Definition iomanX.h:66
#define FIO_S_IFMT
Definition iox_stat.h:39
#define FIO_S_IFDIR
Definition iox_stat.h:45
u32 count
start sector of fragmented bd/file