PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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)
38int pfsFormatArg[3] = { PFS_ZONE_SIZE, PFS_FRAGMENT_OPT, PFS_FRAGMENT };
39#else
40static int pfsFormatArg[1] = { PFS_ZONE_SIZE };
41#endif
42
43#define _OMIT_SYSTEM_PARTITION
44//#define DEBUG
45
46static char *sizesString[9] = {
47 "128M",
48 "256M",
49 "512M",
50 "1G",
51 "2G",
52 "4G",
53 "8G",
54 "16G",
55 "32G"
56};
57
58static int sizesMB[9] = {
59 128,
60 256,
61 512,
62 1024,
63 2048,
64 4096,
65 8192,
66 16384,
67 32768
68};
69
70static void hddUpdateInfo();
71
72static int hddStatusCurrent = 0;
73static u32 hddSize, hddFree, hddMaxPartitionSize;
74
75int 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
90int 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
105int 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
135int 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, 40, "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
253void hddGetInfo(t_hddInfo *info)
254{
255 hddUpdateInfo();
256
257 info->hddSize = hddSize;
258 info->hddFree = hddFree;
259 info->hddMaxPartitionSize = hddMaxPartitionSize;
260}
261
262static 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
295int 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[256];
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 sprintf(fsName, "__%s", name);
316 break;
317 case FS_GROUP_COMMON:
318 sprintf(fsName, "+%s", name);
319 break;
320 default:
321 strcpy(fsName, name);
322 break;
323 }
324
325 // Check if filesystem already exists
326 sprintf(openString, "hdd0:%s", 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 sprintf(openString, "hdd0:%s,,,%s,PFS", 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 sprintf(openString, "hdd0:%s", 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
459int 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
473int 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}
#define ENOSPC
Definition errno.h:75
#define EINVAL
Definition errno.h:63
#define EACCES
Definition errno.h:45
#define EFBIG
Definition errno.h:73
#define HDIOC_TOTALSECTOR
Definition hdd-ioctl.h:98
#define HIOCGETSIZE
Definition hdd-ioctl.h:65
#define HDIOC_MAXSECTOR
Definition hdd-ioctl.h:96
unsigned int private_0
Definition iox_stat.h:102
char filename[40]
Definition libhdd.h:46
int fileSystemGroup
Definition libhdd.h:54
u32 count
start sector of fragmented bd/file