PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
fssk.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 <iomanX.h>
13#include <loadcore.h>
14#include <kerr.h>
15#include <stdio.h>
16#include <sysclib.h>
17#include <thbase.h>
18#include <thevent.h>
19#include <irx.h>
20#include <hdd-ioctl.h>
21
22#include "libpfs.h"
23#include "fssk-ioctl.h"
24#include "fssk.h"
25#include "misc_fssk.h"
26
27#ifdef _IOP
28IRX_ID("fssk", PFS_MAJOR, PFS_MINOR);
29#endif
30
32{
33 struct fsskStatus status;
34 int minFree; // 0x1C
35 int stopFlag; // 0x20
36};
37
38#define FSSK_MAX_PATH_LEVELS 64
39#define FSSK_MAX_PATH_SEG_LENGTH 256
40
41static int fsskEventFlagID;
42static int fsskThreadID;
43static char fsskPathBuffer[FSSK_MAX_PATH_LEVELS][FSSK_MAX_PATH_SEG_LENGTH];
44static int fsskVerbosityLevel = 2;
45
46static pfs_mount_t MainPFSMount = {0}; // FIXME: if not explicitly initialized to 0, the generated IRX would somehow have garbage in this structure.
47
48#define IO_BUFFER_SIZE 256
49#define IO_BUFFER_SIZE_BYTES (IO_BUFFER_SIZE * 512)
50
52static u8 IOBuffer[IO_BUFFER_SIZE_BYTES];
53
54static void fsskPrintPWD(void)
55{
56 int i;
57 char *pName;
58
59 for (i = 0, pName = fsskPathBuffer[0]; (u32)i < fsskRuntimeData.status.PWDLevel; i++, pName += FSSK_MAX_PATH_SEG_LENGTH) {
60 printf("/%s", pName);
61 }
62
63 if (i == 0) {
64 printf("/");
65 }
66}
67
68static int fsskHasSpaceToFree(pfs_cache_t *clink)
69{
70 int result;
71 u32 i;
72 pfs_cache_t *cinode;
73
74 result = 0;
75 cinode = pfsCacheUsedAdd(clink);
76
77 for (i = 0; i < clink->u.inode->number_data; i++) {
78 if (i != 0) {
79 if (pfsFixIndex(i) == 0) {
80 if ((cinode = pfsBlockGetNextSegment(cinode, &result)) == NULL) {
81 break;
82 }
83 }
84 }
85
86 if (clink->pfsMount->num_subs - fsskRuntimeData.status.partsDeleted < cinode->u.inode->data[pfsFixIndex(i)].subpart) {
87 result = 1;
88 break;
89 }
90 }
91
92 fsskRuntimeData.status.inodeBlockCount += clink->u.inode->number_blocks;
93 pfsCacheFree(cinode);
94
95 return result;
96}
97
98static int fsskCalculateSpaceToRemove(pfs_mount_t *mount)
99{
100 u32 PartsToRemove, i, ratio, SizeOfSub, SizeOfSubZones, free, zfree, total_zones;
101
102 PartsToRemove = 0;
103 zfree = mount->zfree;
104 total_zones = mount->total_zones;
105 for (i = mount->num_subs; i != 0; i--, PartsToRemove++) {
106 SizeOfSub = mount->blockDev->getSize(mount->fd, i);
107 SizeOfSubZones = SizeOfSub >> mount->sector_scale;
108 total_zones -= SizeOfSubZones;
109 free = SizeOfSubZones - mount->free_zone[i] - pfsGetBitmapSizeBlocks(mount->sector_scale, SizeOfSub) - 1;
110 if (zfree >= mount->free_zone[i]) {
111 zfree -= mount->free_zone[i];
112 if (zfree >= free) {
113 zfree -= free;
114 ratio = (int)((u64)zfree * 100 / total_zones);
115 PFS_PRINTF("free ratio=%ld, freezone=%ld.\n", ratio, zfree);
116 if (ratio < (u32)(fsskRuntimeData.minFree)) {
117 break;
118 }
119 } else {
120 break;
121 }
122 } else {
123 break;
124 }
125 }
126
127 PFS_PRINTF("%ld partitions will be removed.\n", PartsToRemove);
128
129 return PartsToRemove;
130}
131
132static u16 fsskCalcLastSub(pfs_mount_t *mount)
133{
134 u32 *zfree, MaxFreeRatio, FreeRatio;
135 u16 sub, result;
136
137 for (result = sub = 0, zfree = mount->free_zone, MaxFreeRatio = 0; mount->num_subs - (fsskRuntimeData.status.partsDeleted - 1) != 0; sub++, zfree++) {
138 FreeRatio = ((u64)*zfree) * 100 / (mount->blockDev->getSize(mount->fd, sub) >> mount->sector_scale);
139 if (MaxFreeRatio < FreeRatio) {
140 MaxFreeRatio = FreeRatio;
141 result = sub;
142 }
143 }
144
145 return result;
146}
147
148static int fsskCopyBlock(pfs_mount_t *mount, pfs_blockinfo_t *block1, pfs_blockinfo_t *block2, u32 length)
149{
150 u32 i;
151
152 for (i = 0; i < length; i++) {
153 int result;
154
155 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, block2->subpart, (block2->number + i) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ)) < 0 || ((result = mount->blockDev->transfer(mount->fd, IOBuffer, block1->subpart, (block1->number + i) << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_WRITE)) < 0)) {
156 return result;
157 }
158 }
159
160 return 0;
161}
162
163static pfs_cache_t *fsskCreateIndirectSeg(pfs_cache_t *clink, pfs_cache_t *clink2, pfs_blockinfo_t *data, int *result)
164{
165 pfs_cache_t *clinkfree;
166 pfs_blockinfo_t block;
167
168 *result = 0;
169
170 if (!pfsCacheIsFull()) {
171 block.subpart = data->subpart;
172 block.number = data->number + data->count;
173 if ((*result = pfsBitmapSearchFreeZone(clink->pfsMount, &block, clink->u.inode->number_blocks)) >= 0) {
174 clinkfree = pfsCacheGetData(clink->pfsMount, block.subpart, block.number << clink->pfsMount->inode_scale, PFS_CACHE_FLAG_SEGI | PFS_CACHE_FLAG_NOLOAD, result);
175
176 memset(clinkfree->u.inode, 0, sizeof(pfs_inode_t));
177 clinkfree->u.inode->magic = PFS_SEGI_MAGIC;
178 memcpy(&clinkfree->u.inode->inode_block, &clink->u.inode->inode_block, sizeof(pfs_blockinfo_t));
179 memcpy(&clinkfree->u.inode->last_segment, &clink2->u.inode->data[0], sizeof(pfs_blockinfo_t));
180 memcpy(&clinkfree->u.inode->data[0], &block, sizeof(pfs_blockinfo_t));
181 clinkfree->flags |= PFS_CACHE_FLAG_DIRTY;
182 clink->u.inode->number_blocks += block.count;
183 clink->u.inode->number_data++;
184 memcpy(&clink->u.inode->last_segment, &block, sizeof(pfs_blockinfo_t));
185 clink->u.inode->number_segdesg++;
186 clink->flags |= PFS_CACHE_FLAG_DIRTY;
187 memcpy(&clink2->u.inode->next_segment, &block, sizeof(pfs_blockinfo_t));
188 clink2->flags |= PFS_CACHE_FLAG_DIRTY;
189 pfsCacheFree(clink2);
190
191 return clinkfree;
192 }
193 } else {
194 *result = -ENOMEM;
195 }
196
197 return NULL;
198}
199
200// Very similar to pfsBitmapSearchFreeZone().
201static int fsckBitmapSearchFreeZoneSpecial(pfs_mount_t *pfsMount, pfs_blockinfo_t *bi, u32 max_count, u32 deleted)
202{
203 int num;
204 u32 count, i;
205
206 deleted--;
207 num = pfsMount->num_subs - deleted;
208 if (bi->subpart < num) {
209 bi->subpart = 0;
210 }
211 if (bi->number != 0) {
212 num++;
213 }
214 count = (max_count < 33) ? max_count : 32;
215 if (count < bi->count) {
216 count = bi->count;
217 }
218
219 for (--num; num >= 0; num--) {
220 for (i = count; i != 0; i /= 2) {
221 if ((pfsMount->free_zone[bi->subpart] >= i) && (pfsBitmapAllocZones(pfsMount, bi, i) != 0)) {
222 pfsMount->free_zone[bi->subpart] -= bi->count;
223 pfsMount->zfree -= bi->count;
224 return 0;
225 }
226 }
227
228 bi->subpart++;
229 bi->number = 0;
230 if (pfsMount->num_subs - deleted == bi->subpart) {
231 bi->subpart = 0;
232 }
233 }
234
235 return -ENOSPC;
236}
237
238// I hate this function. :(
239static int fsskMoveInode(pfs_mount_t *mount, pfs_cache_t *dest, pfs_cache_t *start, pfs_dentry_t *dentry)
240{
241 pfs_cache_t *clink, *clink2, *clink3;
242 pfs_blockinfo_t block, block2;
243 int result;
244
245 printf("\t========== Move");
246 if (FIO_S_ISDIR(start->u.inode->mode)) {
247 block.subpart = fsskCalcLastSub(mount);
248 block.number = 0;
249 } else {
250 memcpy(&block, &dest->u.inode->inode_block, sizeof(pfs_blockinfo_t));
251 }
252
253 block.count = 1;
254 if ((result = fsckBitmapSearchFreeZoneSpecial(mount, &block, start->u.inode->number_blocks, fsskRuntimeData.status.partsDeleted)) >= 0) {
255 if ((result = fsskCopyBlock(mount, &block, &start->u.inode->inode_block, 1)) >= 0 &&
256 (clink = pfsCacheGetData(mount, block.subpart, block.number << mount->inode_scale, PFS_CACHE_FLAG_SEGD | PFS_CACHE_FLAG_NOLOAD, &result)) != NULL) {
257 int i;
258
259 memcpy(clink->u.inode, start->u.inode, sizeof(pfs_inode_t));
260 memcpy(&clink->u.inode->inode_block, &block, sizeof(pfs_blockinfo_t));
261 memcpy(&clink->u.inode->last_segment, &block, sizeof(pfs_blockinfo_t));
262 memcpy(&clink->u.inode->data[0], &block, sizeof(pfs_blockinfo_t));
263 clink->u.inode->number_segdesg = 1;
264 clink->u.inode->number_data = 1;
265 clink->u.inode->number_blocks = 1;
266 clink2 = pfsCacheUsedAdd(start);
267 clink3 = pfsCacheUsedAdd(clink);
268
269 for (i = 1; (u32)i < start->u.inode->number_data && result == 0; i++) {
270 if (pfsFixIndex(i) == 0) {
271 if ((clink2 = pfsBlockGetNextSegment(clink2, &result)) == NULL) {
272 break;
273 }
274 } else {
275 memcpy(&block2, &clink2->u.inode->data[pfsFixIndex(i)], sizeof(pfs_blockinfo_t));
276 if (pfsFixIndex(clink->u.inode->number_data - 1) != 0) {
277 int value;
278 if ((value = pfsBitmapAllocateAdditionalZones(mount, clink3->u.inode->data, block2.count)) != 0) {
279 block.subpart = clink3->u.inode->data[0].subpart;
280 block.number = clink3->u.inode->data[0].number + clink3->u.inode->data[0].count;
281 clink3->u.inode->data[0].count += value;
282
283 if ((result = fsskCopyBlock(mount, &block, &block2, value)) < 0) {
284 break;
285 }
286
287 clink->u.inode->number_blocks += value;
288 block2.number += value;
289 block2.count -= value;
290 }
291 }
292 while (block2.count != 0) {
293 if (pfsFixIndex(clink->u.inode->number_data) == 0) {
294 if ((clink3 = fsskCreateIndirectSeg(clink, clink3, clink3->u.inode->data, &result)) == NULL) {
295 break;
296 }
297 }
298
299 block.subpart = clink3->u.inode->data[0].subpart;
300 block.count = block2.count;
301 block.number = clink3->u.inode->data[0].number + clink3->u.inode->data[0].count;
302
303 if ((result = fsckBitmapSearchFreeZoneSpecial(mount, &block, start->u.inode->number_blocks, fsskRuntimeData.status.partsDeleted)) < 0) {
304 break;
305 }
306
307 memcpy(&clink3->u.inode->data[pfsFixIndex(start->u.inode->number_data)], &block, sizeof(pfs_blockinfo_t));
308
309 clink->u.inode->number_data++;
310 if ((result = fsskCopyBlock(mount, &block, &block2, block.count)) < 0) {
311 break;
312 }
313
314 clink->u.inode->number_blocks += block.count;
315 block2.number += block.count;
316 block2.count -= block.count;
317 block2.count--;
318 }
319 }
320 }
321
322 // 0x000009d0
323 pfsCacheFree(clink2);
324 if (result == 0) {
325 dentry->sub = clink->u.inode->inode_block.subpart;
326 dentry->inode = clink->u.inode->inode_block.number;
327 clink3->flags |= PFS_CACHE_FLAG_DIRTY;
328 clink->flags |= PFS_CACHE_FLAG_DIRTY;
329 pfsCacheFree(clink3);
330 pfsCacheFree(clink);
331 pfsBitmapFreeInodeBlocks(start);
332 } else {
333 pfsBitmapFreeInodeBlocks(clink);
334 pfsCacheFree(clink3);
335 pfsCacheFree(clink);
336 }
337 } else
338 pfsBitmapFreeBlockSegment(mount, &block);
339 }
340
341 return result;
342}
343
344static void fsskCheckSelfEntry(pfs_cache_t *SelfInodeClink, pfs_cache_t *SelfDEntryClink, pfs_dentry_t *dentry)
345{
346 if ((SelfInodeClink->sub != dentry->sub) || (SelfInodeClink->u.inode->inode_block.number != dentry->inode)) {
347 PFS_PRINTF("'.' point not itself.\n");
348 dentry->sub = SelfInodeClink->u.inode->inode_block.subpart;
349 dentry->inode = SelfInodeClink->u.inode->inode_block.number;
350 SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
351 }
352}
353
354static void fsskCheckParentEntry(pfs_cache_t *ParentInodeClink, pfs_cache_t *SelfDEntryClink, pfs_dentry_t *dentry)
355{
356 if ((ParentInodeClink->sub != dentry->sub) || (ParentInodeClink->u.inode->inode_block.number != dentry->inode)) {
357 PFS_PRINTF("'..' point not parent.\n");
358 dentry->sub = ParentInodeClink->u.inode->inode_block.subpart;
359 dentry->inode = ParentInodeClink->u.inode->inode_block.number;
360 SelfDEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
361 }
362}
363
364static int fsskCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink);
365
366static int fsskCheckFile(pfs_cache_t *InodeClink, pfs_cache_t *DEntryClink, pfs_dentry_t *dentry)
367{
368 pfs_cache_t *FileInodeDataClink;
369 int result;
370
371 if ((FileInodeDataClink = pfsInodeGetData(InodeClink->pfsMount, dentry->sub, dentry->inode, &result)) != NULL) {
372 if (fsskRuntimeData.status.PWDLevel < FSSK_MAX_PATH_LEVELS - 1) {
373 memset(fsskPathBuffer[fsskRuntimeData.status.PWDLevel], 0, FSSK_MAX_PATH_SEG_LENGTH);
374 strncpy(fsskPathBuffer[fsskRuntimeData.status.PWDLevel], dentry->path, dentry->pLen);
375 fsskRuntimeData.status.PWDLevel++;
376
377 if (fsskVerbosityLevel >= 2) {
378 fsskPrintPWD();
379 if (FIO_S_ISDIR(dentry->aLen)) {
380 printf(": ");
381 }
382 }
383
384 if ((result = fsskHasSpaceToFree(FileInodeDataClink)) > 0) {
385 if ((result = fsskMoveInode(InodeClink->pfsMount, InodeClink, FileInodeDataClink, dentry)) == 0) {
386 DEntryClink->flags |= PFS_CACHE_FLAG_DIRTY;
387 pfsCacheFree(FileInodeDataClink);
388 FileInodeDataClink = pfsInodeGetData(InodeClink->pfsMount, dentry->inode, dentry->sub, &result);
389 }
390 }
391
392 putchar('\n');
393
394 if (result == 0) {
395 if (FIO_S_ISDIR(dentry->aLen)) {
396 fsskRuntimeData.status.directories++;
397 result = fsskCheckFiles(InodeClink, FileInodeDataClink);
398 } else {
399 fsskRuntimeData.status.files++;
400 }
401 }
402
403 fsskRuntimeData.status.PWDLevel--;
404 } else {
405 PFS_PRINTF("error: exceed max directory depth.\n");
406 result = -ENOMEM;
407 }
408 }
409
410 return result;
411}
412
413static int fsskCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink)
414{
415 pfs_blockpos_t BlockPosition;
416 pfs_dentry_t *pDEntry, *pDEntryEnd;
417 int result;
418 u32 inodeOffset, dEntrySize; // inodeOffset doesn't seem to be 64-bit, even though the inode size field is 64-bits wide.
419 pfs_cache_t *DEntryClink;
420
421 if (CheckThreadStack() < 128) {
422 PFS_PRINTF("error: there is no stack, giving up.\n");
423 return -ENOMEM;
424 }
425
426 inodeOffset = 0;
427 BlockPosition.inode = pfsCacheUsedAdd(InodeClink);
428 BlockPosition.block_segment = 1;
429 BlockPosition.block_offset = 0;
430 BlockPosition.byte_offset = 0;
431 if ((DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
432 pfsCacheFree(BlockPosition.inode);
433 return result;
434 }
435 pDEntry = DEntryClink->u.dentry;
436
437 while (inodeOffset < InodeClink->u.inode->size) {
438 if (pDEntry >= (pfs_dentry_t *)(DEntryClink->u.data + 1024)) {
439 pfsCacheFree(DEntryClink);
440 if ((result = pfsInodeSync(&BlockPosition, 1024, InodeClink->u.inode->number_data)) != 0 || (DEntryClink = pfsGetDentriesChunk(&BlockPosition, &result)) == NULL) {
441 break;
442 }
443 }
444
445 for (pDEntry = DEntryClink->u.dentry, pDEntryEnd = DEntryClink->u.dentry + 1; pDEntry < pDEntryEnd; pDEntry = (pfs_dentry_t *)((u8 *)pDEntry + dEntrySize), inodeOffset += dEntrySize) {
446 if (fsskRuntimeData.stopFlag != 0) {
447 goto end;
448 }
449
450 dEntrySize = pDEntry->aLen & 0x0FFF;
451
452 if (dEntrySize & 3) {
453 PFS_PRINTF("error: directory entry is not aligned.\n");
454 result = -EINVAL;
455 goto end;
456 }
457
458 if (dEntrySize < (u32)((pDEntry->pLen + 11) & ~3)) {
459 PFS_PRINTF("error: directory entry is too small.\n");
460 result = -EINVAL;
461 goto end;
462 }
463
464 if (pDEntryEnd < (pfs_dentry_t *)((u8 *)pDEntry + dEntrySize)) {
465 PFS_PRINTF("error: directory entry is too long.\n");
466 result = -EINVAL;
467 goto end;
468 }
469
470 if (pDEntry->inode != 0) {
471 if ((pDEntry->pLen == 1) && (pDEntry->path[0] == '.')) {
472 fsskCheckSelfEntry(InodeClink, DEntryClink, pDEntry);
473 } else if ((pDEntry->pLen == 2) && (pDEntry->path[0] == '.')) {
474 fsskCheckParentEntry(ParentInodeClink, DEntryClink, pDEntry);
475 } else {
476 if ((result = fsskCheckFile(InodeClink, DEntryClink, pDEntry)) < 0) {
477 goto end;
478 }
479 }
480 }
481 }
482
483 if (fsskRuntimeData.stopFlag != 0) {
484 break;
485 }
486 }
487
488end:
489 pfsCacheFree(DEntryClink);
490 pfsCacheFree(BlockPosition.inode);
491
492 return result;
493}
494
495static void FsskThread(pfs_mount_t *mount)
496{
497 pfs_cache_t *clink;
498 pfs_dentry_t dentry;
499 int result, i;
500
501 if ((fsskRuntimeData.status.partsDeleted = fsskCalculateSpaceToRemove(mount)) != 0) {
502 if ((clink = pfsInodeGetData(mount, mount->root_dir.subpart, mount->root_dir.number, &result)) != NULL) {
503 if ((result = fsskHasSpaceToFree(clink)) > 0) {
504 PFS_PRINTF("root directory will be moved.\n");
505 if ((result = fsskMoveInode(mount, clink, clink, &dentry)) == 0) {
506 pfsCacheFree(clink);
507 if ((clink = pfsInodeGetData(mount, dentry.sub, dentry.inode, &result)) != NULL) {
508 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ)) == 0) {
509 mount->root_dir.subpart = dentry.sub;
510 mount->root_dir.number = dentry.inode;
511 memcpy(&((pfs_super_block_t *)IOBuffer)->root, &mount->root_dir, sizeof(pfs_blockinfo_t));
512 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_BACKUP_SECTOR, 1, PFS_IO_MODE_WRITE)) == 0) {
513 result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
514 }
515 mount->blockDev->flushCache(mount->fd);
516 }
517 }
518 }
519 }
520
521 if (result >= 0) {
522 fsskRuntimeData.status.directories++;
523 result = fsskCheckFiles(clink, clink);
524 pfsCacheFree(clink);
525 pfsCacheFlushAllDirty(mount);
526 if (result == 0) {
527 if (fsskRuntimeData.stopFlag == 0) {
528 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_READ)) == 0) {
529 ((pfs_super_block_t *)IOBuffer)->num_subs -= fsskRuntimeData.status.partsDeleted;
530 mount->num_subs -= fsskRuntimeData.status.partsDeleted;
531 if ((result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_BACKUP_SECTOR, 1, PFS_IO_MODE_WRITE)) == 0) {
532 result = mount->blockDev->transfer(mount->fd, IOBuffer, 0, PFS_SUPER_SECTOR, 1, PFS_IO_MODE_WRITE);
533 }
534
535 mount->blockDev->flushCache(mount->fd);
536 }
537
538 for (i = 0; (u32)i < fsskRuntimeData.status.partsDeleted && result == 0; i++) {
539 iomanX_ioctl2(mount->fd, HIOCDELSUB, NULL, 0, NULL, 0);
540 }
541 }
542 }
543
544 if (result < 0) {
545 fsskRuntimeData.status.hasError = 1;
546 }
547 } else {
548 pfsCacheFree(clink);
549 fsskRuntimeData.status.hasError = 1;
550 }
551 } else {
552 PFS_PRINTF("error: cannot read root directory.\n");
553 fsskRuntimeData.status.hasError = 1;
554 goto end2;
555 }
556 } else {
557 PFS_PRINTF("error: there is no space to remove.\n");
558 goto end2;
559 }
560
561end2:
562 SetEventFlag(fsskEventFlagID, 1);
563}
564
565static int FsskOpen(iomanX_iop_file_t *fd, const char *name, int flags, int mode)
566{
567 int blockfd, result;
568 iox_stat_t StatData;
569 pfs_block_device_t *pblockDevData;
570
571 (void)flags;
572
573 fsskVerbosityLevel = (mode & 0xF0) >> 4;
574
575 if (MainPFSMount.fd) {
576 return -EBUSY;
577 }
578
579 if ((result = iomanX_getstat(name, &StatData)) < 0) {
580 PFS_PRINTF("error: could not get status.\n");
581 return result;
582 }
583
584 if (StatData.mode != APA_TYPE_PFS) {
585 PFS_PRINTF("error: not PFS.\n");
586 return -EINVAL;
587 }
588
589 if ((pblockDevData = pfsGetBlockDeviceTable(name)) == NULL)
590 return -ENXIO;
591
592 if ((blockfd = iomanX_open(name, O_RDWR)) < 0) {
593 PFS_PRINTF("error: cannot open.\n");
594 return blockfd;
595 }
596
597 memset(&MainPFSMount, 0, sizeof(MainPFSMount));
598 MainPFSMount.fd = blockfd;
599 MainPFSMount.blockDev = pblockDevData;
600
601 if (pfsMountSuperBlock(&MainPFSMount) >= 0) {
602 memset(&fsskRuntimeData, 0, sizeof(fsskRuntimeData));
603
604 fsskRuntimeData.status.zoneUsed = MainPFSMount.total_zones - MainPFSMount.zfree;
605 fsskRuntimeData.minFree = 3;
606 fd->privdata = &MainPFSMount;
607 result = 0;
608 } else {
609 MainPFSMount.fd = 0;
610 PFS_PRINTF("error: cannot continue.\n");
611 }
612
613 return result;
614}
615
616static int FsskClose(iomanX_iop_file_t *fd)
617{
618 iomanX_close(((pfs_mount_t *)fd->privdata)->fd);
619 pfsCacheClose((pfs_mount_t *)fd->privdata);
620 memset(fd->privdata, 0, sizeof(pfs_mount_t));
621
622 return 0;
623}
624
625static int fsskSimGetStat(pfs_mount_t *mount)
626{
627 int result;
628
629 fsskRuntimeData.status.partsDeleted = fsskCalculateSpaceToRemove(mount);
630 result = 0;
631 if (mount->num_subs - fsskRuntimeData.status.partsDeleted < mount->num_subs) {
632 int i;
633 for (i = mount->num_subs; i != 0; i--) {
634 result += mount->blockDev->getSize(mount->fd, i);
635 }
636 }
637
638 return result;
639}
640
641static int fsskGetEstimatedTime(pfs_mount_t *mount, int *result)
642{
643 unsigned int i;
644 u64 clock;
645 iop_sys_clock_t SysClock1, SysClock2, SysClockDiff;
646 u32 sec, usec;
647
648 clock = 1000000;
649 for (i = 0; i < 4; i++) {
650 GetSystemTime(&SysClock1);
651 mount->blockDev->transfer(mount->fd, IOBuffer, 0, 1 << mount->sector_scale, 1 << mount->sector_scale, PFS_IO_MODE_READ);
652 GetSystemTime(&SysClock2);
653
654 SysClockDiff.lo = SysClock2.lo - SysClock1.lo;
655 SysClockDiff.hi = SysClock2.hi - SysClock1.hi - (SysClock2.lo < SysClock1.lo);
656 SysClock2USec(&SysClockDiff, &sec, &usec);
657
658 PFS_PRINTF("%ld system clocks = %ld.%06ld sec\n", SysClockDiff.lo, sec, usec);
659
660 if (usec < clock)
661 clock = usec;
662 }
663
664 if ((*result = ((clock + 400) * fsskRuntimeData.status.zoneUsed / 1000000)) == 0)
665 *result = 1;
666
667 return 0;
668}
669
670static int FsskIoctl2(iomanX_iop_file_t *fd, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
671{
672 int result;
673 u32 FlagBits;
674
675 (void)arglen;
676 (void)buflen;
677
678 switch (cmd) {
679 case FSSK_IOCTL2_CMD_GET_ESTIMATE:
680 result = fsskGetEstimatedTime(fd->privdata, buf);
681 break;
682 case FSSK_IOCTL2_CMD_START:
683 result = StartThread(fsskThreadID, fd->privdata);
684 break;
685 case FSSK_IOCTL2_CMD_WAIT:
686 result = WaitEventFlag(fsskEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
687 break;
688 case FSSK_IOCTL2_CMD_POLL:
689 result = PollEventFlag(fsskEventFlagID, 1, WEF_OR | WEF_CLEAR, &FlagBits);
690 if (result == KE_EVF_COND) {
691 result = 1;
692 }
693 break;
694 case FSSK_IOCTL2_CMD_GET_STATUS:
695 memcpy(buf, &fsskRuntimeData.status, sizeof(struct fsskStatus));
696 result = 0;
697 break;
698 case FSSK_IOCTL2_CMD_STOP:
699 fsskRuntimeData.stopFlag = 1;
700 result = 0;
701 break;
702 case FSSK_IOCTL2_CMD_SET_MINFREE:
703 if (*(int *)arg >= 4)
704 fsskRuntimeData.minFree = *(int *)arg;
705 result = 0;
706 break;
707 case FSSK_IOCTL2_CMD_SIM:
708 result = fsskSimGetStat(fd->privdata);
709 break;
710 default:
711 result = 0;
712 }
713
714 return result;
715}
716
717IOMANX_RETURN_VALUE_IMPL(0);
718
719static iomanX_iop_device_ops_t FsskDeviceOps = {
720 IOMANX_RETURN_VALUE(0), // init
721 IOMANX_RETURN_VALUE(0), // deinit
722 IOMANX_RETURN_VALUE(0), // format
723 &FsskOpen, // open
724 &FsskClose, // close
725 IOMANX_RETURN_VALUE(0), // read
726 IOMANX_RETURN_VALUE(0), // write
727 IOMANX_RETURN_VALUE(0), // lseek
728 IOMANX_RETURN_VALUE(0), // ioctl
729 IOMANX_RETURN_VALUE(0), // remove
730 IOMANX_RETURN_VALUE(0), // mkdir
731 IOMANX_RETURN_VALUE(0), // rmdir
732 IOMANX_RETURN_VALUE(0), // dopen
733 IOMANX_RETURN_VALUE(0), // dclose
734 IOMANX_RETURN_VALUE(0), // dread
735 IOMANX_RETURN_VALUE(0), // getstat
736 IOMANX_RETURN_VALUE(0), // chstat
737 IOMANX_RETURN_VALUE(0), // rename
738 IOMANX_RETURN_VALUE(0), // chdir
739 IOMANX_RETURN_VALUE(0), // sync
740 IOMANX_RETURN_VALUE(0), // mount
741 IOMANX_RETURN_VALUE(0), // umount
742 IOMANX_RETURN_VALUE_S64(0), // lseek64
743 IOMANX_RETURN_VALUE(0), // devctl
744 IOMANX_RETURN_VALUE(0), // symlink
745 IOMANX_RETURN_VALUE(0), // readlink
746 &FsskIoctl2, // ioctl2
747};
748
749static iomanX_iop_device_t FsskDevice = {
750 "fssk",
751 IOP_DT_FSEXT | IOP_DT_FS,
752 1,
753 "FSSK",
754 &FsskDeviceOps};
755
756static int DisplayUsageHelp(void)
757{
758 PFS_PRINTF("error: Usage: fssk [-n <num>]\n");
759 return MODULE_NO_RESIDENT_END;
760}
761
762int PFS_ENTRYPOINT(int argc, char **argv)
763{
764 int buffers;
765
766 buffers = 0x7E;
767 for (argc--, argv++; argc > 0 && ((*argv)[0] == '-'); argc--, argv++) {
768 if (!strcmp("-n", *argv)) {
769 argv++;
770 if (--argc > 0) {
771 if (strtol(*argv, NULL, 10) < buffers) {
772 buffers = strtol(*argv, NULL, 10);
773 }
774 } else {
775 return DisplayUsageHelp();
776 }
777 } else {
778 return DisplayUsageHelp();
779 }
780 }
781
782 PFS_PRINTF("max depth %d, %d buffers.\n", FSSK_MAX_PATH_LEVELS - 1, buffers);
783
784 if (pfsCacheInit(buffers, 1024) < 0) {
785 PFS_PRINTF("error: cache initialization failed.\n");
786 return MODULE_NO_RESIDENT_END;
787 }
788
789 if ((fsskEventFlagID = fsskCreateEventFlag()) < 0) {
790 return MODULE_NO_RESIDENT_END;
791 }
792
793 if ((fsskThreadID = fsskCreateThread((void *)&FsskThread, 0x2080)) < 0) {
794 return MODULE_NO_RESIDENT_END;
795 }
796
797 iomanX_DelDrv(FsskDevice.name);
798 if (iomanX_AddDrv(&FsskDevice) == 0) {
799 PFS_PRINTF("version %04x driver start.\n", IRX_VER(PFS_MAJOR, PFS_MINOR));
800 return MODULE_RESIDENT_END;
801 }
802
803 return MODULE_NO_RESIDENT_END;
804}
#define ENOSPC
Definition errno.h:75
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define ENOMEM
Definition errno.h:43
#define EBUSY
Definition errno.h:51
#define IOP_DT_FSEXT
Definition iomanX.h:66
u32 count
start sector of fragmented bd/file