Fix a bug (in revision 426) which made "Mode 3 - Unhook Syscalls" un-effectivei ...
[open-ps2-loader.git] / modules / ps2fs / pfs_fioctl.c
blobe15e5b43467254ab8b53629a0c3c2b392bcc33f5
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.
10 # $Id: pfs_fioctl.c 577 2004-09-14 14:41:46Z pixel $
11 # PFS ioctl and devctl related routines
14 #include "pfs.h"
16 int pfsIoctl(iop_file_t *f, unsigned long arg, void *param)
18 return -1;
21 int pfsDevctl(iop_file_t *f, const char *name, int cmd, void *arg, size_t arglen, void *buf, size_t buflen)
23 pfs_mount_t *pfsMount;
24 int rv=0;
26 if(!(pfsMount=fioGetMountedUnit(f->unit)))
27 return -ENODEV;
29 switch(cmd)
31 case PFS_DEVCTL_GET_ZONE_SIZE:
32 rv=pfsMount->zsize;
33 break;
35 case PFS_DEVCTL_GET_ZONE_FREE:
36 rv=pfsMount->zfree;
37 break;
39 case PFS_DEVCTL_CLOSE_ALL:
40 devctlCloseAll();
41 hddFlushCache(pfsMount->fd);
42 break;
44 case PFS_DEVCTL_CLEAR_STAT:
45 rv=devctlFsckStat(pfsMount, MODE_REMOVE_FLAG);
46 break;
48 case PFS_DEVCTL_GET_STAT:
49 rv=devctlFsckStat(pfsMount, MODE_CHECK_FLAG);
50 break;
52 case PFS_DEVCTL_SET_UID:
53 pfsMount->uid=*(u16 *)(arg);
54 break;
56 case PFS_DEVCTL_SET_GID:
57 pfsMount->gid=*(u16 *)(arg);
58 break;
60 case PFS_DEVCTL_SHOW_BITMAP:
61 bitmapShow(pfsMount);
62 break;
64 default:
65 rv=-EINVAL;
66 break;
69 SignalSema(pfsFioSema);
71 return rv;
74 int pfsIoctl2(iop_file_t *f, int cmd, void *arg, size_t arglen, void *buf, size_t buflen)
76 int rv;
77 pfs_file_slot_t *fileSlot = (pfs_file_slot_t *)f->privdata;
78 pfs_mount_t *pfsMount;
80 if(f->mode & O_DIROPEN)
81 if(cmd==PFS_IOCTL2_ATTR_READ)
82 return -EISDIR;
84 if(!(f->mode & O_WRONLY)) {
85 if(cmd!=PFS_IOCTL2_ATTR_LOOKUP)
86 if(cmd!=PFS_IOCTL2_ATTR_READ)
87 return -EACCES;
89 if((rv=checkFileSlot(fileSlot))<0)
90 return rv;
91 pfsMount=fileSlot->clink->pfsMount;
93 switch(cmd)
95 case PFS_IOCTL2_MALLOC:
96 rv=ioctl2Alloc(fileSlot->clink, *(int *)(arg), 1);
97 break;
99 case PFS_IOCTL2_FREE:
100 ioctl2Free(fileSlot->clink);
101 break;
103 case PFS_IOCTL2_ATTR_ADD:
104 case PFS_IOCTL2_ATTR_DEL:
105 case PFS_IOCTL2_ATTR_LOOKUP:
106 case PFS_IOCTL2_ATTR_READ:
107 rv=ioctl2Attr(fileSlot->clink, cmd, arg, buf, &fileSlot->aentryOffset);
108 break;
110 case PFS_IOCTL2_GET_INODE:
111 memcpy(buf, fileSlot->clink->u.inode, sizeof(pfs_inode));
112 rv = sizeof(pfs_inode);
113 break;
115 default:
116 rv=-EINVAL;
117 break;
120 if(pfsMount->flags & FIO_ATTR_WRITEABLE)
121 cacheFlushAllDirty(pfsMount);
122 rv=checkForLastError(pfsMount, rv);
123 SignalSema(pfsFioSema);
125 return rv;
128 int ioctl2Attr(pfs_cache_t *clink, int cmd, void *arg, void *outbuf, u32 *offset)
129 { // attr set, attr delete, attr lookup, attr read cmds
130 int rv;
131 pfs_cache_t *flink;
133 if((flink=cacheGetData(clink->pfsMount, clink->sub, clink->sector+1
134 ,CACHE_FLAG_NOTHING, &rv))==NULL)
135 return rv;
137 switch(cmd)
139 case PFS_IOCTL2_ATTR_ADD:
140 rv=ioctl2AttrAdd(flink, arg);
141 break;
143 case PFS_IOCTL2_ATTR_DEL:
144 rv=ioctl2AttrDelete(flink, arg);
145 break;
147 case PFS_IOCTL2_ATTR_LOOKUP:
148 rv=ioctl2AttrLoopUp(flink, arg, outbuf);
149 break;
151 case PFS_IOCTL2_ATTR_READ:
152 rv=ioctl2AttrRead(flink, outbuf, offset);
153 break;
156 cacheAdd(flink);
158 return rv;
161 void devctlCloseAll()
163 u32 i;
165 for(i=0;i < pfsConfig.maxOpen;i++)
167 if(fileSlots[i].fd)
168 closeFileSlot(&fileSlots[i]);
170 for(i=0;i < pfsConfig.maxOpen;i++)
172 pfs_mount_t *pfsMount;
173 if((pfsMount=getMountedUnit(i))!=NULL)
174 cacheFlushAllDirty(pfsMount);
179 int devctlFsckStat(pfs_mount_t *pfsMount, int mode)
181 int rv;
182 pfs_cache_t *clink;
184 if((clink=cacheAllocClean(&rv))!=NULL){
185 rv=fsckStat(pfsMount, clink->u.superblock, FSCK_STAT_ERROR_0x02, mode);
186 cacheAdd(clink);
188 return rv;
191 pfs_aentry_t *getAentry(pfs_cache_t *clink, char *key, char *value, int mode)
192 { // mode 0=lookup, 1=add, 2=delete
193 int kLen, fullsize;
194 pfs_aentry_t *aentry=clink->u.aentry;
195 pfs_aentry_t *aentryLast=NULL;
196 u32 end;
198 kLen=strlen(key);
199 fullsize=(kLen+strlen(value)+7) & ~3;
200 for(end=(u32)aentry+1024;(u32)end < (u32)(aentry); (char *)aentry+=aentry->aLen)
202 if(aentry->aLen & 3)
203 printf("ps2fs: Error: attrib-entry allocated length/4 != 0\n");
204 if(aentry->aLen < ((aentry->kLen+aentry->vLen+7) & ~3))
206 printf("ps2fs: Panic: attrib-entry is too small\n");
207 return NULL;
209 if((u32)end < (u32)aentry+aentry->aLen)
210 printf("ps2fs: Error: attrib-emtru too big\n");
212 switch(mode)
214 case 0:// lookup
215 if(kLen==aentry->kLen)
216 if(memcmp(key, aentry->str, kLen)==0)
217 return aentry;
218 break;
220 case 1:// add
221 if(aentry->kLen==0)
223 if(aentry->aLen>=fullsize)
224 return aentry;
226 if(aentry->aLen - ((aentry->kLen+aentry->vLen+7) & ~3) < fullsize)
227 continue;
228 return aentry;
230 default:// delete
231 if(kLen==aentry->kLen)
233 if(memcmp(key, aentry->str, kLen)==0)
235 if(aentryLast!=NULL)
237 aentryLast->aLen+=aentry->aLen;
238 return aentry;
240 // delete it :P
241 aentry->kLen=0;
242 aentry->vLen=0;
243 return aentry;
246 aentryLast=aentry;
247 break;
251 return NULL;
254 int ioctl2AttrAdd(pfs_cache_t *clink, pfs_ioctl2attr_t *attr)
256 u32 kLen, vLen;
257 pfs_aentry_t *aentry;
258 u32 tmp;
260 // input check
261 kLen=strlen(attr->key);
262 vLen=strlen(attr->value);
263 if(kLen>=256 || vLen>=256) // max size safe e check
264 return -EINVAL;
266 if(kLen==0 || vLen==0) // no input check
267 return -EINVAL;
269 if(getAentry(clink, attr->key, NULL, 0))
270 return -EEXIST;
271 if(!(aentry=getAentry(clink, attr->key, attr->value, 1)))
272 return -ENOSPC;
274 if(aentry->kLen==0)
275 tmp=aentry->aLen;
276 else
277 tmp=aentry->aLen-((aentry->kLen+(aentry->vLen + 7)) & ~3);
279 aentry->aLen-=tmp;
280 (char *)aentry+=aentry->aLen;
281 aentry->kLen=kLen;
282 aentry->vLen=vLen;
283 aentry->aLen=tmp;
284 memcpy(&aentry->str[0], attr->key, aentry->kLen);
285 memcpy(&aentry->str[aentry->kLen], attr->value, aentry->vLen);
286 clink->flags|=CACHE_FLAG_DIRTY;
288 return 0;
291 int ioctl2AttrDelete(pfs_cache_t *clink, void *arg)
293 pfs_aentry_t *aentry;
295 if((aentry=getAentry(clink, arg, 0, 2))==NULL)
296 return -ENOENT;
297 clink->flags|=CACHE_FLAG_DIRTY;
298 return 0;
301 int ioctl2AttrLoopUp(pfs_cache_t *clink, char *key, char *value)
303 pfs_aentry_t *aentry;
305 if((aentry=getAentry(clink, key, 0, 0))){
306 memcpy(value, &aentry->str[aentry->kLen], aentry->vLen);
307 value[aentry->vLen]=0;
308 return aentry->vLen;
310 return -ENOENT;
313 int ioctl2AttrRead(pfs_cache_t *clink, pfs_ioctl2attr_t *attr, u32 *offset)
315 pfs_aentry_t *aentry;
317 if(*offset >= 1024)
318 return 0;
319 do {
320 aentry=(pfs_aentry_t *)((u32)(clink->u.inode)+*offset);
321 memcpy(attr->key, &aentry->str[0], aentry->kLen);
322 attr->key[aentry->kLen]=0;
323 memcpy(attr->value, &aentry->str[aentry->kLen], aentry->vLen);
324 attr->value[aentry->vLen]=0;
325 *offset+=aentry->aLen; // next
326 if(aentry->kLen!=0)
327 break;
328 } while(*offset < 1024);
330 return aentry->kLen;
334 int ioctl2Alloc(pfs_cache_t *clink, int msize, int mode)
336 pfs_blockpos_t blockpos;
337 int result=0;
338 u32 val;
339 int zsize;
341 zsize=clink->pfsMount->zsize;
342 val=((msize-1 + zsize) & (-zsize)) / zsize;
344 if(mode==0)
345 if (((clink->u.inode->number_blocks-clink->u.inode->number_segdesg) *(u64)zsize)
346 >= (clink->u.inode->size + msize))
347 return 0;
349 if((blockpos.inode = blockGetLastSegmentDescriptorInode(clink, &result)))
351 blockpos.block_offset=blockpos.byte_offset=0;
352 blockpos.block_segment=clink->u.inode->number_data-1;
353 val-=blockExpandSegment(clink, &blockpos, val);
354 while (val && ((result=blockAllocNewSegment(clink, &blockpos, val))>=0)){
355 val-=result;
356 result=0;
358 cacheAdd(blockpos.inode);
360 return result;
363 void ioctl2Free(pfs_cache_t *pfree)
365 pfs_blockinfo b;
366 int result;
367 pfs_mount_t *pfsMount = pfree->pfsMount;
368 pfs_inode *inode = pfree->u.inode;
369 u32 nextsegdesc = 1, limit = inode->number_data, i, j = 0, zones;
370 pfs_blockinfo *bi;
371 pfs_cache_t *clink;
373 zones = inode->size / pfsMount->zsize;
374 if(inode->size % pfsMount->zsize)
375 zones++;
376 if(inode->number_segdesg + zones == inode->number_blocks)
377 return;
379 j = zones;
380 b.number = 0;
381 clink = cacheUsedAdd(pfree);
383 // iterate through each of the block segments used by the inode
384 for (i = 1; i < limit && j; i++)
386 if(fixIndex(i) == 0)
388 if ((clink = blockGetNextSegment(clink, &result)) == 0)
389 return;
391 nextsegdesc++;
393 else
394 if(j < clink->u.inode->data[fixIndex(i)].count)
396 clink->u.inode->data[fixIndex(i)].count -= j;
397 b.subpart = clink->u.inode->data[fixIndex(i)].subpart;
398 b.count = j;
399 b.number = clink->u.inode->data[fixIndex(i)].number +
400 clink->u.inode->data[fixIndex(i)].count;
401 j = 0;
402 clink->flags |= CACHE_FLAG_DIRTY;
404 else
405 j -= clink->u.inode->data[fixIndex(i)].count;
408 pfree->u.inode->number_data = i;
409 pfree->u.inode->number_blocks = zones + nextsegdesc;
410 pfree->u.inode->number_segdesg = nextsegdesc;
411 pfree->u.inode->last_segment.number = clink->u.inode->data[0].number;
412 pfree->u.inode->last_segment.subpart= clink->u.inode->data[0].subpart;
413 pfree->u.inode->last_segment.count = clink->u.inode->data[0].count;
414 pfree->flags |= CACHE_FLAG_DIRTY;
416 if (b.number)
417 bitmapFreeBlockSegment(pfsMount, &b);
419 while(i < limit)
421 if (fixIndex(i) == 0)
423 if((clink = blockGetNextSegment(clink, &result)) == 0)
424 return;
426 bi = &clink->u.inode->data[fixIndex(i++)];
427 bitmapFreeBlockSegment(pfsMount, bi);
428 cacheMarkClean(pfsMount, bi->subpart, bi->number<<pfsMount->inode_scale,
429 (bi->number+bi->count)<<pfsMount->inode_scale);
432 cacheAdd(clink);