PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
pfs_fioctl.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# PFS ioctl and devctl related routines
11*/
12
13#include <stdio.h>
14#ifdef _IOP
15#include <sysclib.h>
16#else
17#include <string.h>
18#endif
19#include <errno.h>
20#include <iomanX.h>
21#include <thsemap.h>
22#include <hdd-ioctl.h>
23
24#include "libpfs.h"
25#include "pfs.h"
26#include "pfs_fio.h"
27#include "pfs_fioctl.h"
28
29extern pfs_config_t pfsConfig;
30extern int pfsFioSema;
31extern pfs_file_slot_t *pfsFileSlots;
32
33#ifdef PFS_IOCTL2_INC_CHECKSUM
34extern u32 pfsBlockSize;
35#endif
36
37enum PFS_AENTRY_MODE {
38 PFS_AENTRY_MODE_LOOKUP = 0,
39 PFS_AENTRY_MODE_ADD,
40 PFS_AENTRY_MODE_DELETE
41};
42
44// Function declarations
45
46static int devctlFsckStat(pfs_mount_t *pfsMount, int mode);
47
48#ifdef PFS_IOCTL2_INC_CHECKSUM
49static int ioctl2InvalidateInode(pfs_cache_t *clink);
50#endif
51static int ioctl2Attr(pfs_cache_t *clink, int cmd, void *arg, void *outbuf, u32 *offset);
52static pfs_aentry_t *getAentry(pfs_cache_t *clink, char *key, char *value, int mode);
53static int ioctl2AttrAdd(pfs_cache_t *clink, pfs_ioctl2attr_t *attr);
54static int ioctl2AttrDelete(pfs_cache_t *clink, void *arg);
55static int ioctl2AttrLookUp(pfs_cache_t *clink, char *key, char *value);
56static int ioctl2AttrRead(pfs_cache_t *clink, pfs_ioctl2attr_t *attr, u32 *unkbuf);
57
58int pfsFioIoctl(iomanX_iop_file_t *f, int cmd, void *param)
59{
60 (void)f;
61 (void)cmd;
62 (void)param;
63
64 return -1;
65}
66
67int pfsFioDevctl(iomanX_iop_file_t *f, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
68{
69 pfs_mount_t *pfsMount;
70 int rv=0;
71
72 (void)name;
73 (void)arg;
74 (void)arglen;
75 (void)buf;
76 (void)buflen;
77
78 if(!(pfsMount=pfsFioGetMountedUnit(f->unit)))
79 return -ENODEV;
80#ifdef PFS_SUPPORT_BHDD
81 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
82 {
83 SignalSema(pfsFioSema);
84 return -ENODEV;
85 }
86#endif
87 switch(cmd)
88 {
89 case PDIOC_ZONESZ:
90 rv=pfsMount->zsize;
91 break;
92
93 case PDIOC_ZONEFREE:
94 rv=pfsMount->zfree;
95 break;
96
97 case PDIOC_CLOSEALL:
98 pfsFioDevctlCloseAll();
99 break;
100
101 case PDIOC_CLRFSCKSTAT:
102 rv=devctlFsckStat(pfsMount, PFS_MODE_REMOVE_FLAG);
103 break;
104
105 case PDIOC_GETFSCKSTAT:
106 rv=devctlFsckStat(pfsMount, PFS_MODE_CHECK_FLAG);
107 break;
108
109 case PDIOC_SHOWBITMAP:
110 pfsBitmapShow(pfsMount);
111 break;
112
113 default:
114 rv=-EINVAL;
115 break;
116
117 }
118 SignalSema(pfsFioSema);
119
120 return rv;
121}
122
123#ifdef PFS_IOCTL2_INC_CHECKSUM
124static int ioctl2InvalidateInode(pfs_cache_t *clink)
125{
126 clink->u.inode->checksum++;
127 return clink->pfsMount->blockDev->transfer(clink->pfsMount->fd, clink->u.inode, clink->sub, clink->block << pfsBlockSize, 1 << pfsBlockSize, PFS_IO_MODE_WRITE);
128}
129#endif
130
131int pfsFioIoctl2(iomanX_iop_file_t *f, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
132{
133 int rv;
134 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
135 pfs_mount_t *pfsMount;
136
137 (void)arglen;
138 (void)buflen;
139
140 if(f->mode & FIO_O_DIROPEN)
141 if(cmd==PIOCATTRREAD)
142 return -EISDIR;
143
144 if(!(f->mode & FIO_O_WRONLY))
145 {
146 switch(cmd)
147 {
148 case PIOCATTRLOOKUP:
149 case PIOCATTRREAD:
150 case PIOCINVINODE:
151 break;
152 default:
153 return -EACCES;
154 }
155 }
156 if((rv=pfsFioCheckFileSlot(fileSlot))<0)
157 return rv;
158 pfsMount=fileSlot->clink->pfsMount;
159#ifdef PFS_SUPPORT_BHDD
160 if (strcmp(pfsMount->blockDev->devName, "bhdd") == 0)
161 return -EBADF;
162#endif
163 switch(cmd)
164 {
165 case PIOCALLOC:
166 rv=pfsAllocZones(fileSlot->clink, *(int *)(arg), 1);
167 break;
168
169 case PIOCFREE:
170 pfsFreeZones(fileSlot->clink);
171 break;
172
173 case PIOCATTRADD:
174 case PIOCATTRDEL:
175 case PIOCATTRLOOKUP:
176 case PIOCATTRREAD:
177 rv=ioctl2Attr(fileSlot->clink, cmd, arg, buf, &fileSlot->aentryOffset);
178 break;
179
180#ifdef PFS_IOCTL2_INC_CHECKSUM
181 case PIOCINVINODE:
182 rv=ioctl2InvalidateInode(fileSlot->clink);
183 break;
184#endif
185
186 default:
187 rv=-EINVAL;
188 break;
189 }
190
191 if(pfsMount->flags & PFS_FIO_ATTR_WRITEABLE)
192 pfsCacheFlushAllDirty(pfsMount);
193 rv=pfsFioCheckForLastError(pfsMount, rv);
194 SignalSema(pfsFioSema);
195
196 return rv;
197}
198
199static int ioctl2Attr(pfs_cache_t *clink, int cmd, void *arg, void *outbuf, u32 *offset)
200{ // attr set, attr delete, attr lookup, attr read cmds
201 int rv;
202 pfs_cache_t *flink;
203
204 if((flink=pfsCacheGetData(clink->pfsMount, clink->sub, clink->block+1
205 ,PFS_CACHE_FLAG_NOTHING, &rv))==NULL)
206 return rv;
207
208 switch(cmd)
209 {
210 case PIOCATTRADD:
211 rv=ioctl2AttrAdd(flink, arg);
212 break;
213
214 case PIOCATTRDEL:
215 rv=ioctl2AttrDelete(flink, arg);
216 break;
217
218 case PIOCATTRLOOKUP:
219 rv=ioctl2AttrLookUp(flink, arg, outbuf);
220 break;
221
222 case PIOCATTRREAD:
223 rv=ioctl2AttrRead(flink, outbuf, offset);
224 break;
225
226 }
227 pfsCacheFree(flink);
228
229 return rv;
230}
231
232void pfsFioDevctlCloseAll(void)
233{
234 s32 i;
235
236 for(i=0;(u32)i < pfsConfig.maxOpen;i++)
237 {
238 if(pfsFileSlots[i].fd)
239 pfsFioCloseFileSlot(&pfsFileSlots[i]);
240 }
241 for(i=0;(u32)i < pfsConfig.maxOpen;i++)
242 {
243 pfs_mount_t *pfsMount;
244 if((pfsMount=pfsGetMountedUnit(i))!=NULL)
245 pfsCacheFlushAllDirty(pfsMount);
246
247 }
248}
249
250static int devctlFsckStat(pfs_mount_t *pfsMount, int mode)
251{
252 int rv;
253 pfs_cache_t *clink;
254
255 if((clink=pfsCacheAllocClean(&rv))!=NULL){
256 rv=pfsFsckStat(pfsMount, clink->u.superblock, PFS_FSCK_STAT_ERRORS_FIXED, mode);
257 pfsCacheFree(clink);
258 }
259 return rv;
260}
261
262static pfs_aentry_t *getAentry(pfs_cache_t *clink, char *key, char *value, int mode)
263{
264 int kLen, fullsize;
265 pfs_aentry_t *aentry=clink->u.aentry;
266 pfs_aentry_t *aentryLast=NULL;
267 pfs_aentry_t *end;
268
269 kLen=strlen(key);
270 fullsize = 0;
271 if (value != NULL)
272 {
273 fullsize=(kLen+strlen(value)+7) & ~3;
274 }
275 for(end=(pfs_aentry_t *)((u8*)aentry+1024);aentry < end; aentry=(pfs_aentry_t *)((u8*)aentry+aentry->aLen))
276 { //Other than critical errors, do nothing about the filesystem errors.
277 if(aentry->aLen & 3)
278 PFS_PRINTF(PFS_DRV_NAME" Error: aentry allocated length/4 != 0\n");
279 if(aentry->aLen < ((aentry->kLen+aentry->vLen+7) & ~3))
280 {
281 PFS_PRINTF(PFS_DRV_NAME" Panic: aentry is too small\n");
282 return NULL;
283 }
284 if(end < (pfs_aentry_t*)((u8*)aentry+aentry->aLen))
285 PFS_PRINTF(PFS_DRV_NAME" Error: aentry too big\n");
286
287 switch(mode)
288 {
289 case PFS_AENTRY_MODE_LOOKUP:
290 if(kLen==aentry->kLen)
291 if(memcmp(key, aentry->str, kLen)==0)
292 return aentry;
293 break;
294
295 case PFS_AENTRY_MODE_ADD:
296 if(aentry->kLen==0)
297 {
298 if(aentry->aLen>=fullsize)
299 return aentry;
300 }
301 if(aentry->aLen - ((aentry->kLen+aentry->vLen+7) & ~3) < fullsize)
302 continue;
303 return aentry;
304
305 case PFS_AENTRY_MODE_DELETE:
306 default:
307 if(kLen==aentry->kLen)
308 {
309 if(memcmp(key, aentry->str, kLen)==0)
310 {
311 if(aentryLast!=NULL)
312 {
313 aentryLast->aLen+=aentry->aLen;
314 return aentry;
315 }
316 // delete it :P
317 aentry->kLen=0;
318 aentry->vLen=0;
319 return aentry;
320 }
321 }
322 aentryLast=aentry;
323 break;
324
325 }
326 }
327 return NULL;
328}
329
330static int ioctl2AttrAdd(pfs_cache_t *clink, pfs_ioctl2attr_t *attr)
331{
332 u32 kLen, vLen;
333 pfs_aentry_t *aentry;
334 u32 tmp;
335
336 // input check
337 kLen=strlen(attr->key);
338 vLen=strlen(attr->value);
339 if(kLen>=PFS_AENTRY_KEY_MAX || vLen>=PFS_AENTRY_VALUE_MAX) // max size bounds check
340 return -EINVAL;
341
342 if(kLen==0 || vLen==0) // no input check
343 return -EINVAL;
344
345 if(getAentry(clink, attr->key, NULL, PFS_AENTRY_MODE_LOOKUP))
346 return -EEXIST;
347 if((aentry=getAentry(clink, attr->key, attr->value, PFS_AENTRY_MODE_ADD)) == NULL)
348 return -ENOSPC;
349
350 if(aentry->kLen==0)
351 tmp=aentry->aLen;
352 else
353 tmp=aentry->aLen-((aentry->kLen+(aentry->vLen + 7)) & 0x3FC); //The only case that uses 0x3FC within the whole PFS driver.
354
355 aentry->aLen-=tmp;
356 aentry = (pfs_aentry_t*)((u8 *)aentry + aentry->aLen);
357 aentry->kLen=kLen;
358 aentry->vLen=vLen;
359 aentry->aLen=tmp;
360 memcpy(&aentry->str[0], attr->key, aentry->kLen);
361 memcpy(&aentry->str[aentry->kLen], attr->value, aentry->vLen);
362 clink->flags|=PFS_CACHE_FLAG_DIRTY;
363
364 return 0;
365}
366
367static int ioctl2AttrDelete(pfs_cache_t *clink, void *arg)
368{
369 if(getAentry(clink, arg, NULL, PFS_AENTRY_MODE_DELETE) == NULL)
370 return -ENOENT;
371 clink->flags|=PFS_CACHE_FLAG_DIRTY;
372 return 0;
373}
374
375static int ioctl2AttrLookUp(pfs_cache_t *clink, char *key, char *value)
376{
377 pfs_aentry_t *aentry;
378
379 if((aentry=getAentry(clink, key, NULL, PFS_AENTRY_MODE_LOOKUP)) != NULL)
380 {
381 memcpy(value, &aentry->str[aentry->kLen], aentry->vLen);
382 value[aentry->vLen]=0;
383 return aentry->vLen;
384 }
385 return -ENOENT;
386}
387
388static int ioctl2AttrRead(pfs_cache_t *clink, pfs_ioctl2attr_t *attr, u32 *offset)
389{
390 pfs_aentry_t *aentry;
391
392 if(*offset >= 1024)
393 return 0;
394 do {
395 aentry=(pfs_aentry_t *)((u8*)clink->u.inode+*offset);
396 memcpy(attr->key, &aentry->str[0], aentry->kLen);
397 attr->key[aentry->kLen]=0;
398 memcpy(attr->value, &aentry->str[aentry->kLen], aentry->vLen);
399 attr->value[aentry->vLen]=0;
400 *offset+=aentry->aLen; // next
401 if(aentry->kLen!=0)
402 break;
403 } while(*offset < 1024);
404
405 return aentry->kLen;
406}
#define ENOENT
Definition errno.h:23
#define ENOSPC
Definition errno.h:75
#define EEXIST
Definition errno.h:53
#define EINVAL
Definition errno.h:63
#define ENODEV
Definition errno.h:57
#define EACCES
Definition errno.h:45
#define EBADF
Definition errno.h:37
#define EISDIR
Definition errno.h:61
void * privdata
Definition iomanX.h:78