PS2SDK
PS2 Homebrew Libraries
libhdd.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 <stdio.h>
12 #include <tamtypes.h>
13 #include <errno.h>
14 #include <kernel.h>
15 #include <string.h>
16 #include <sifrpc.h>
17 #include <loadfile.h>
18 #include <iopheap.h>
19 #include <stdlib.h>
20 
21 // PS2DRV includes
22 #include "sys/fcntl.h"
23 #include "sys/stat.h"
24 #include "sys/ioctl.h"
25 #include "errno.h"
26 
27 #include "libhdd.h"
28 
29 #define NEWLIB_PORT_AWARE
30 #include "fileXio_rpc.h"
31 #include "io_common.h"
32 
33 #define PFS_ZONE_SIZE 8192
34 #define PFS_FRAGMENT_OPT 0x00002d66 //"-f"
35 #define PFS_FRAGMENT 0x00000000
36 
37 #if (PFS_FRAGMENT != 0)
38 static const int pfsFormatArg[3] = { PFS_ZONE_SIZE, PFS_FRAGMENT_OPT, PFS_FRAGMENT };
39 #else
40 static const int pfsFormatArg[1] = { PFS_ZONE_SIZE };
41 #endif
42 
43 #define _OMIT_SYSTEM_PARTITION
44 //#define DEBUG
45 
46 static char *sizesString[9] = {
47  "128M",
48  "256M",
49  "512M",
50  "1G",
51  "2G",
52  "4G",
53  "8G",
54  "16G",
55  "32G"
56 };
57 
58 static int sizesMB[9] = {
59  128,
60  256,
61  512,
62  1024,
63  2048,
64  4096,
65  8192,
66  16384,
67  32768
68 };
69 
70 static void hddUpdateInfo();
71 
72 static int hddStatusCurrent = 0;
73 static u32 hddSize, hddFree, hddMaxPartitionSize;
74 
75 int hddCheckPresent()
76 {
77  int rv;
78 
79  if(!hddStatusCurrent)
80  hddUpdateInfo();
81 
82  rv = fileXioDevctl("hdd0:", HDIOC_STATUS, NULL, 0, NULL, 0);
83 
84  if((rv >= 3) || (rv < 0))
85  return -1;
86  else
87  return 0;
88 }
89 
90 int hddCheckFormatted()
91 {
92  int rv;
93 
94  if(!hddStatusCurrent)
95  hddUpdateInfo();
96 
97  rv = fileXioDevctl("hdd0:", HDIOC_STATUS, NULL, 0, NULL, 0);
98  if((rv >= 1) || (rv < 0))
99  return -1;
100  else
101  return 0;
102 }
103 
104 
105 int hddFormat()
106 {
107  int retVal, i;
108  const char *partitionList[] = {
109  "hdd0:__net",
110  "hdd0:__system",
111  "hdd0:__sysconf",
112  "hdd0:__common",
113  NULL
114  };
115 
116  if(!hddStatusCurrent)
117  hddUpdateInfo();
118 
119  retVal = fileXioFormat("hdd0:", NULL, NULL, 0);
120  if(retVal < 0)
121  return retVal;
122 
123  for(i = 0; partitionList[i] != NULL; i++)
124  {
125  retVal = fileXioFormat("pfs:", partitionList[i], (const char*)&pfsFormatArg, sizeof(pfsFormatArg));
126  if(retVal < 0)
127  return retVal;
128  }
129 
130  hddUpdateInfo();
131 
132  return 0;
133 }
134 
135 int hddGetFilesystemList(t_hddFilesystem hddFs[], int maxEntries)
136 {
137  iox_dirent_t dirEnt;
138  int count = 0;
139  u32 size = 0;
140  int hddFd;
141  int rv;
142 
143  if(!hddStatusCurrent)
144  hddUpdateInfo();
145 
146  hddFd = fileXioDopen("hdd0:");
147 
148  if(hddFd < 0)
149  return hddFd;
150 
151  rv = fileXioDread(hddFd, &dirEnt);
152 
153  while((rv > 0) && (count < maxEntries))
154  {
155  int i;
156  int partitionFd;
157  u32 zoneFree, zoneSize;
158 
159  // We only want to know about main partitions (non-empty ones at that :P)
160  if((dirEnt.stat.attr & ATTR_SUB_PARTITION) || (dirEnt.stat.mode == FS_TYPE_EMPTY))
161  {
162  rv = fileXioDread(hddFd, &dirEnt);
163  continue;
164  }
165 
166  memset(&hddFs[count], 0, sizeof(t_hddFilesystem));
167  snprintf(hddFs[count].filename, sizeof(hddFs[count].filename), "hdd0:%.34s", dirEnt.name);
168 
169  // Work out filesystem type
170  if((dirEnt.name[0] == '_') && (dirEnt.name[1] == '_'))
171  {
172  hddFs[count].fileSystemGroup = FS_GROUP_SYSTEM;
173  strcpy(hddFs[count].name, &dirEnt.name[2]);
174  }
175  else if(dirEnt.name[0] == FS_COMMON_PREFIX)
176  {
177  hddFs[count].fileSystemGroup = FS_GROUP_COMMON;
178  strcpy(hddFs[count].name, &dirEnt.name[1]);
179  }
180  else
181  {
182  hddFs[count].fileSystemGroup = FS_GROUP_APPLICATION;
183  strcpy(hddFs[count].name, dirEnt.name);
184  }
185 
186 #ifdef _OMIT_SYSTEM_PARTITION
187  if(hddFs[count].fileSystemGroup == FS_GROUP_SYSTEM)
188  {
189  rv = fileXioDread(hddFd, &dirEnt);
190  continue;
191  }
192 #endif
193 
194 #ifdef DEBUG
195  printf("> Filename: %s\n> Name: %s\n> Type: %d\n", hddFs[count].filename, hddFs[count].name, hddFs[count].fileSystemGroup);
196 #endif
197 
198  // Calculate filesystem size
199  partitionFd = fileXioOpen(hddFs[count].filename, FIO_O_RDONLY);
200 
201  // If we failed to open the partition, then a password is probably set
202  // (usually this means we have tried to access a game partition). We
203  // dont want to return un-accessible game partitions in the filesystem list..
204  if(partitionFd < 0)
205  {
206  rv = fileXioDread(hddFd, &dirEnt);
207  continue;
208  }
209 
210  for(i = 0, size = 0; (unsigned int)i < dirEnt.stat.private_0 + 1; i++)
211  {
212  rv = fileXioIoctl2(partitionFd, HIOCGETSIZE, &i, 4, NULL, 0);
213  size += (u32)rv / 2048; //Equal to, but avoids overflows of: rv * 512 / 1024 / 1024;
214  }
215 
216  fileXioClose(partitionFd);
217 
218  hddFs[count].size = size;
219 
220  // Get filesystem free space & format status
221  hddFs[count].freeSpace = 0;
222  hddFs[count].formatted = 0;
223 
224  if(dirEnt.stat.mode == FS_TYPE_PFS)
225  {
226  rv = fileXioMount("pfs0:", hddFs[count].filename, FIO_MT_RDONLY);
227  if(rv == 0)
228  {
229 
230  zoneFree = fileXioDevctl("pfs0:", PDIOC_ZONEFREE, NULL, 0, NULL, 0);
231  zoneSize = fileXioDevctl("pfs0:", PDIOC_ZONESZ, NULL, 0, NULL, 0);
232 
233  hddFs[count].freeSpace = zoneFree * zoneSize / 1024 / 1024;
234  hddFs[count].formatted = 1;
235 
236  fileXioUmount("pfs0:");
237  }
238  }
239 
240 #ifdef DEBUG
241  printf("> Formatted: %d\n> Size: %d\n> Free: %d\n", hddFs[count].formatted, (int)hddFs[count].size, (int)hddFs[count].freeSpace);
242 #endif
243 
244  count++;
245  rv = fileXioDread(hddFd, &dirEnt);
246  }
247 
248  fileXioDclose(hddFd);
249 
250  return count;
251 }
252 
253 void hddGetInfo(t_hddInfo *info)
254 {
255  hddUpdateInfo();
256 
257  info->hddSize = hddSize;
258  info->hddFree = hddFree;
259  info->hddMaxPartitionSize = hddMaxPartitionSize;
260 }
261 
262 static void hddUpdateInfo()
263 {
264  iox_dirent_t infoDirEnt;
265  int rv;
266  int hddFd;
267  u32 hddUsed = 0;
268 
269  hddSize = (u32)fileXioDevctl("hdd0:", HDIOC_TOTALSECTOR, NULL, 0, NULL, 0) / 2048; //sectors * 512 / 1024 / 1024;
270 
271 /* This gives inaccurate results, due to it being an approximation.
272  fileXioDevctl("hdd0:", HDIOC_FREESECTOR, NULL, 0, &rv, 4);
273  hddFree = rv * 512 / 1024 / 1024;
274 */
275  hddFd = fileXioDopen("hdd0:");
276  if(hddFd < 0) // For when a HDD is not connected!
277  return;
278 
279  rv = fileXioDread(hddFd, &infoDirEnt);
280  while(rv > 0)
281  {
282  if(infoDirEnt.stat.mode != FS_TYPE_EMPTY)
283  hddUsed += infoDirEnt.stat.size / 2048; //Equal to, but avoids overflows of: infoDirEnt.stat.size * 512 / 1024 / 1024;
284 
285  rv = fileXioDread(hddFd, &infoDirEnt);
286  }
287  fileXioDclose(hddFd);
288  hddFree = hddSize - hddUsed;
289 
290  hddMaxPartitionSize = (u32)fileXioDevctl("hdd0:", HDIOC_MAXSECTOR, NULL, 0, NULL, 0) / 2048; //Equal to, but avoids overflows of: sectors * 512 / 1024 / 1024;
291 
292  hddStatusCurrent = 1;
293 }
294 
295 int hddMakeFilesystem(int fsSizeMB, char *name, int type)
296 {
297  int maxIndex;
298  int useIndex;
299  int partSize;
300  int fsSizeLeft = fsSizeMB;
301  int partFd;
302  char openString[268];
303  char fsName[256];
304  int retVal;
305 
306  if(!hddStatusCurrent)
307  hddUpdateInfo();
308 
309  if(fsSizeMB % 128)
310  return -EINVAL;
311 
312  switch(type)
313  {
314  case FS_GROUP_SYSTEM:
315  snprintf(fsName, sizeof(fsName), "__%s", name);
316  break;
317  case FS_GROUP_COMMON:
318  snprintf(fsName, sizeof(fsName), "+%s", name);
319  break;
320  default:
321  strlcpy(fsName, name, sizeof(fsName));
322  break;
323  }
324 
325  // Check if filesystem already exists
326  snprintf(openString, sizeof(openString), "hdd0:%.*s", (int)(sizeof(fsName) - 1), fsName);
327  partFd = fileXioOpen(openString, FIO_O_RDONLY);
328  if(partFd > 0 || partFd == -EACCES) // Filesystem already exists
329  {
330  fileXioClose(partFd);
331  return -1;
332  }
333 
334  // Get index for max partition size
335  for(maxIndex = 0; maxIndex < 9; maxIndex++)
336  if((u32)(sizesMB[maxIndex]) == hddMaxPartitionSize)
337  break;
338 
339  // Get index of size we will use to create main partition
340  for(useIndex = maxIndex; sizesMB[useIndex] > fsSizeMB; useIndex--);
341 
342  for(partSize = sizesMB[useIndex]; useIndex >= 0; useIndex--,partSize = sizesMB[useIndex])
343  {
344 #ifdef DEBUG
345  printf(">>> Attempting to create main partition, size %d MB\n", partSize);
346 #endif
347 
348  snprintf(openString, sizeof(openString), "hdd0:%.*s,,,%s,PFS", (int)(sizeof(fsName) - 1), fsName, sizesString[useIndex]);
349 #ifdef DEBUG
350  printf(">>> openString = %s\n", openString);
351 #endif
352 
353  partFd = fileXioOpen(openString, FIO_O_RDWR | FIO_O_CREAT);
354  if(partFd >= 0)
355  break;
356  else {
357  if(partFd != -ENOSPC)
358  {
359 #ifdef DEBUG
360  printf(">>> Could not create Main Partition (error %d)!\n", partFd);
361 #endif
362  return partFd;
363  }
364  }
365  }
366 
367  if(useIndex < 0)
368  {
369 #ifdef DEBUG
370  printf(">>> Could not create Main Partition (no space)!\n");
371 #endif
372  return -ENOSPC;
373  }
374 
375  fsSizeLeft -= partSize;
376 #ifdef DEBUG
377  printf(">>> Main partition of %d MB created!\n", partSize);
378 #endif
379 
380  while(fsSizeLeft)
381  {
382 
383  // Adjust size if necessary
384  if(fsSizeLeft < partSize)
385  {
386 #ifdef DEBUG
387  printf(">>> Adjusting sub size: %d MB to ", sizesMB[useIndex]);
388 #endif
389  for(useIndex = maxIndex; sizesMB[useIndex] > fsSizeLeft; useIndex--);
390  partSize = sizesMB[useIndex];
391  maxIndex = useIndex;
392 #ifdef DEBUG
393  printf("%d MB\n", sizesMB[useIndex]);
394 #endif
395  }
396 
397  // Try and allocate sub
398 #ifdef DEBUG
399  printf(">>> Attempting to create sub partition of size %d MB\n", sizesMB[useIndex]);
400 #endif
401  retVal = fileXioIoctl2(partFd, HIOCADDSUB, sizesString[useIndex], strlen(sizesString[useIndex]) + 1, NULL, 0);
402  if(retVal == -ENOSPC)
403  {
404  // If sub alloc fails due to size, we decrease size and try again.
405  // If we've run out of sizes, break the loop (give up)
406  useIndex--;
407  partSize = sizesMB[useIndex];
408  maxIndex = useIndex;
409 
410  if(useIndex < 0)
411  {
412 #ifdef DEBUG
413  printf(">>> Out of sizes to try. Giving up.\n");
414 #endif
415  break;
416  }
417 #ifdef DEBUG
418  printf(">>> Subpartition alloc FAILED! Trying with size of %d MB\n", partSize);
419 #endif
420 
421  continue;
422  }
423  // If we've reached the max number of subs, bail.
424  else if(retVal == -EFBIG)
425  break;
426  else if(retVal >= 0)
427  {
428 #ifdef DEBUG
429  printf(">>> Sub creation successfull!\n");
430 #endif
431  }
432  else
433  {
434 #ifdef DEBUG
435  printf(">>> Unknown error while creating sub: %d\n", retVal);
436 #endif
437  }
438 
439  fsSizeLeft -= sizesMB[useIndex];
440  }
441 
442  fileXioClose(partFd);
443 
444  snprintf(openString, sizeof(openString), "hdd0:%.*s", (int)(sizeof(fsName) - 1), fsName);
445  retVal = fileXioFormat("pfs:", openString, (const char*)&pfsFormatArg, sizeof(pfsFormatArg));
446  if(retVal < 0)
447  {
448 #ifdef DEBUG
449  printf(">>> Failed to format new partition: %d\n", retVal);
450 #endif
451  return retVal;
452  }
453 
454  hddUpdateInfo();
455 
456  return fsSizeMB - fsSizeLeft;
457 }
458 
459 int hddRemoveFilesystem(t_hddFilesystem *fs)
460 {
461  int rv;
462 
463  if(!hddStatusCurrent)
464  hddUpdateInfo();
465 
466  rv = fileXioRemove(fs->filename);
467 
468  hddUpdateInfo();
469 
470  return rv;
471 }
472 
473 int hddExpandFilesystem(t_hddFilesystem *fs, int extraMB)
474 {
475  int maxIndex;
476  int useIndex;
477  int partSize;
478  int fsSizeLeft = extraMB;
479  int partFd;
480  int retVal;
481 
482  if(!hddStatusCurrent)
483  hddUpdateInfo();
484 
485  if(extraMB % 128)
486  return -EINVAL;
487 
488  // Get index for max partition size
489  for(maxIndex = 0; maxIndex < 9; maxIndex++)
490  if((u32)(sizesMB[maxIndex]) == hddMaxPartitionSize)
491  break;
492 
493  // Get index of size we will use to create new subs
494  for(useIndex = maxIndex; sizesMB[useIndex] > extraMB; useIndex--);
495 
496  partSize = sizesMB[useIndex];
497 
498  // Open partition
499  partFd = fileXioOpen(fs->filename, FIO_O_RDWR);
500  if(partFd < 0)
501  return partFd;
502 
503  while(fsSizeLeft)
504  {
505  // Adjust size if necessary
506  if(fsSizeLeft < partSize)
507  {
508 #ifdef DEBUG
509  printf(">>> Adjusting sub size: %d MB to ", sizesMB[useIndex]);
510 #endif
511  for(useIndex = maxIndex; sizesMB[useIndex] > fsSizeLeft; useIndex--);
512  partSize = sizesMB[useIndex];
513  maxIndex = useIndex;
514 #ifdef DEBUG
515  printf("%d MB\n", sizesMB[useIndex]);
516 #endif
517  }
518 
519  // Try and allocate new sub
520 #ifdef DEBUG
521  printf(">>> Attempting to create sub partition of size %d MB\n", sizesMB[useIndex]);
522 #endif
523  retVal = fileXioIoctl2(partFd, HIOCADDSUB, sizesString[useIndex], strlen(sizesString[useIndex]) + 1, NULL, 0);
524  if(retVal == -ENOSPC)
525  {
526  // If sub alloc fails due to size, we decrease size and try again.
527  // If we've run out of sizes, break the loop (give up)
528  useIndex--;
529  partSize = sizesMB[useIndex];
530  maxIndex = useIndex;
531 
532  if(useIndex < 0)
533  {
534 #ifdef DEBUG
535  printf(">>> Out of sizes to try. Giving up.\n");
536 #endif
537  break;
538  }
539 #ifdef DEBUG
540  printf(">>> Subpartition alloc FAILED! Trying with size of %d MB\n", partSize);
541 #endif
542 
543  continue;
544  }
545  // If we've reached the max number of subs, bail.
546  else if(retVal == -EFBIG)
547  break;
548  else if(retVal >= 0)
549  {
550 #ifdef DEBUG
551  printf(">>> Sub creation successfull!\n");
552 #endif
553  }
554  else
555  {
556 #ifdef DEBUG
557  printf(">>> Unknown error while creating sub: %d\n", retVal);
558 #endif
559  }
560 
561  fsSizeLeft -= sizesMB[useIndex];
562  }
563 
564  fileXioClose(partFd);
565 
566  hddUpdateInfo();
567 
568  return extraMB - fsSizeLeft;
569 }
kernel.h
io_common.h
PFS_ZONE_SIZE
#define PFS_ZONE_SIZE
Definition: ps2_fio.c:1308
t_hddFilesystem
Definition: libhdd.h:41
HIOCGETSIZE
#define HIOCGETSIZE
Definition: hdd-ioctl.h:65
HDIOC_TOTALSECTOR
#define HDIOC_TOTALSECTOR
Definition: hdd-ioctl.h:98
s_info
Definition: xprintf.c:78
loadfile.h
t_hddFilesystem::size
u32 size
Definition: libhdd.h:48
t_hddFilesystem::filename
char filename[40]
Definition: libhdd.h:46
t_hddFilesystem::fileSystemGroup
int fileSystemGroup
Definition: libhdd.h:54
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
iopheap.h
HDIOC_MAXSECTOR
#define HDIOC_MAXSECTOR
Definition: hdd-ioctl.h:96
fileXio_rpc.h
t_hddFilesystem::formatted
int formatted
Definition: libhdd.h:50
tamtypes.h
stdio.h
ENOSPC
#define ENOSPC
Definition: errno.h:75
iox_dirent_t
Definition: iox_stat.h:111
ioctl.h
libhdd.h
iox_stat_t::private_0
unsigned int private_0
Definition: iox_stat.h:102
t_hddInfo
Definition: libhdd.h:57
EINVAL
#define EINVAL
Definition: errno.h:63
stdlib.h
EACCES
#define EACCES
Definition: errno.h:45
EFBIG
#define EFBIG
Definition: errno.h:73
errno.h
t_hddFilesystem::freeSpace
u32 freeSpace
Definition: libhdd.h:52