PS2SDK
PS2 Homebrew Libraries
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
28 IRX_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 
41 static int fsskEventFlagID;
42 static int fsskThreadID;
43 static char fsskPathBuffer[FSSK_MAX_PATH_LEVELS][FSSK_MAX_PATH_SEG_LENGTH];
44 static int fsskVerbosityLevel = 2;
45 
46 static 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 
51 static struct fsskRuntimeData fsskRuntimeData;
52 static u8 IOBuffer[IO_BUFFER_SIZE_BYTES];
53 
54 static 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 
68 static 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 
98 static 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 
132 static 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 
148 static 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 
163 static 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().
201 static 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. :(
239 static 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 
344 static 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 
354 static 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 
364 static int fsskCheckFiles(pfs_cache_t *ParentInodeClink, pfs_cache_t *InodeClink);
365 
366 static 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 
413 static 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 
488 end:
489  pfsCacheFree(DEntryClink);
490  pfsCacheFree(BlockPosition.inode);
491 
492  return result;
493 }
494 
495 static 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 
561 end2:
562  SetEventFlag(fsskEventFlagID, 1);
563 }
564 
565 static 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 
616 static 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 
625 static 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 
641 static 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 
670 static 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 
717 IOMANX_RETURN_VALUE_IMPL(0);
718 
719 static 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 
749 static iomanX_iop_device_t FsskDevice = {
750  "fssk",
751  IOP_DT_FSEXT | IOP_DT_FS,
752  1,
753  "FSSK",
754  &FsskDeviceOps};
755 
756 static int DisplayUsageHelp(void)
757 {
758  PFS_PRINTF("error: Usage: fssk [-n <num>]\n");
759  return MODULE_NO_RESIDENT_END;
760 }
761 
762 int 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 }
iomanX.h
fsskRuntimeData
Definition: fssk.c:31
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
thbase.h
_iomanX_iop_file
Definition: iomanX.h:70
sysclib.h
ENOMEM
#define ENOMEM
Definition: errno.h:43
ENXIO
#define ENXIO
Definition: errno.h:31
loadcore.h
pfs_super_block_t
Definition: libpfs.h:134
pfs_blockinfo_t
Definition: libpfs.h:116
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
fsskStatus
Definition: fssk-ioctl.h:14
_iomanX_iop_device_ops
Definition: iomanX.h:95
EBUSY
#define EBUSY
Definition: errno.h:51
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
ENOSPC
#define ENOSPC
Definition: errno.h:75
pfs_inode_t
Definition: libpfs.h:146
pfs_blockpos_t
Definition: libpfs.h:213
pfs_mount_t
Definition: libpfs.h:178
EINVAL
#define EINVAL
Definition: errno.h:63
thevent.h
_iop_sys_clock
Definition: thbase.h:87
errno.h
kerr.h
pfs_dentry_t
Definition: libpfs.h:107