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