Suggestion from "mgh".
[open-ps2-loader.git] / modules / ps2fs / dir.c
blob519144d8357781a73a33d5338defedc113fd79de
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: dir.c 1158 2005-06-13 22:31:13Z oopo $
11 # PFS directory parsing routines
14 #include "pfs.h"
16 // Gets a dir entry from the inode specified by clink
17 pfs_cache_t *getDentry(pfs_cache_t *clink, char *path, pfs_dentry **dentry, u32 *size, int option)
19 pfs_blockpos_t block_pos;
20 u32 result;
21 pfs_dentry *d;
22 u16 aLen;
23 pfs_dentry *d2;
24 pfs_cache_t *dentCache;
25 u32 dentryLen=0;
26 int len=0;
28 if (path)
30 len = strlen(path);
31 dentryLen = (len+8+3) &~4;
33 *size = 0;
35 block_pos.inode = cacheUsedAdd(clink);
36 block_pos.block_segment = 1;
37 block_pos.block_offset = 0;
38 block_pos.byte_offset = 0;
39 dentCache = getDentriesChunk(&block_pos, (int *)&result);
41 if (dentCache)
43 d2=d=dentCache->u.dentry;
44 while(*size < clink->u.inode->size)
46 // Read another dentry chunk if we need to
47 if ((int)d2 >= ((int)dentCache->u.inode + metaSize))
49 if (inodeSync(&block_pos, metaSize, clink->u.inode->number_data))
50 break;
51 cacheAdd(dentCache);
53 if ((dentCache=getDentriesChunk(&block_pos, (int *)&result))==0)
54 break;
55 d=dentCache->u.dentry;
58 for (d2=(pfs_dentry*)((int)d+512); d < d2; (int)d+=aLen)
60 aLen=(d->aLen & 0xFFF);
62 if (aLen & 3){
63 printf("ps2fs: Error: dir-entry allocated length/4 != 0\n");
64 goto _exit;
66 if (aLen < ((d->pLen + 8 + 3) & 0x1FC)){
67 printf("ps2fs: Error: dir-entry is too small\n");
68 goto _exit;
70 if ((u32)d2 < ((u32)d + aLen)){
71 printf("ps2fs: Error: dir-entry across sectors\n");
72 goto _exit;
75 // decide if the current dentry meets the required criteria, based on 'option'
76 switch(option)
78 case 0: // result = 1 when paths are equal
79 result = (len==d->pLen) && (memcmp(path, d->path, d->pLen)==0);
80 break;
81 case 1: // hrm..
82 result = ((d->inode) || (aLen < dentryLen)) ? ((aLen - ((d->pLen + 8 + 3) & 0x1FC))
83 > dentryLen) : 1;
84 break;
85 case 2: // result = 1 when dir path is not empty, "." or ".."
86 result = d->pLen && strcmp(d->path, ".") && strcmp(d->path, "..");
87 break;
88 default:
89 goto _exit;
92 if (result)
94 *dentry=d;
95 cacheAdd(block_pos.inode);
96 return dentCache;
98 *size+=aLen;
101 _exit: cacheAdd(dentCache);
103 cacheAdd(block_pos.inode);
104 return NULL;
107 pfs_cache_t *getDentriesChunk(pfs_blockpos_t *position, int *result)
109 pfs_blockinfo *bi;
110 pfs_mount_t *pfsMount=position->inode->pfsMount;
112 bi = &position->inode->u.inode->data[fixIndex(position->block_segment)];
114 return cacheGetData(pfsMount, bi->subpart,
115 ((bi->number + position->block_offset) << pfsMount->inode_scale) +
116 position->byte_offset / metaSize, CACHE_FLAG_NOTHING, result);
119 int getNextDentry(pfs_cache_t *clink, pfs_blockpos_t *blockpos, u32 *position, char *name, pfs_blockinfo *bi)
121 int result;
122 pfs_cache_t *dcache;
123 pfs_dentry *dentry;
124 u32 len=0;
126 // loop until a non-empty entry is found or until the end of the dentry chunk is reached
127 while((len == 0) && (*position < clink->u.inode->size))
130 if (!(dcache=getDentriesChunk(blockpos, &result)))
132 dprintf("ps2fs: couldnt get dentries chunk for dread!\n");
133 break;
136 dentry = (pfs_dentry*)((u32)dcache->u.data + (blockpos->byte_offset % metaSize));
138 len = dentry->pLen;
139 memcpy(name, dentry->path, len);
140 name[len] = '\0';
142 bi->subpart = dentry->sub;
143 bi->number = dentry->inode;
144 cacheAdd(dcache);
146 *position += dentry->aLen & 0xFFF;
148 // update blockpos
149 if (inodeSync(blockpos, dentry->aLen & 0xFFF, clink->u.inode->number_data))
150 break;
153 return len;
156 pfs_cache_t *getDentriesAtPos(pfs_cache_t *clink, u64 position, int *offset, int *result)
158 pfs_blockpos_t blockpos;
159 pfs_cache_t *r;
160 *result=blockInitPos(clink, &blockpos, position);
161 if (*result) return 0;
163 *offset=blockpos.byte_offset % metaSize;
165 r=getDentriesChunk(&blockpos, result);
166 cacheAdd(blockpos.inode);
168 return r;
171 pfs_cache_t *fillInDentry(pfs_cache_t *clink, pfs_dentry *dentry, char *path1, pfs_blockinfo *bi, u32 len, u16 mode)
173 dentry->inode=bi->number;
174 dentry->sub=bi->subpart;
175 dentry->pLen=strlen(path1);
176 dentry->aLen=len | (mode & FIO_S_IFMT);
177 memcpy(dentry->path, path1, dentry->pLen & 0xFF);
179 return clink;
182 pfs_cache_t *dirAddEntry(pfs_cache_t *dir, char *filename, pfs_blockinfo *bi, u16 mode, int *result)
184 pfs_dentry *dentry;
185 u32 size;
186 u32 len;
187 pfs_cache_t *dcache;
189 dcache=getDentry(dir, filename, &dentry, &size, 1);
190 if (dcache){
191 len=dentry->aLen & 0xFFF;
192 if (dentry->pLen)
193 len-=(dentry->pLen + 11) & 0x1FC;
194 dentry->aLen=(dentry->aLen & FIO_S_IFMT) | ((dentry->aLen & 0xFFF) - len);
195 (u32)dentry+=dentry->aLen & 0xFFF;
196 }else{
197 int offset;
199 if ((*result=ioctl2Alloc(dir, sizeof(pfs_dentry), 0))<0)
200 return NULL;
201 dcache=getDentriesAtPos(dir, dir->u.inode->size, &offset, result);
202 if (dcache==NULL)
203 return NULL;
205 dir->u.inode->size += sizeof(pfs_dentry);
207 dentry=(pfs_dentry*)((u32)dcache->u.dentry+offset);
208 len=sizeof(pfs_dentry);
210 return fillInDentry(dcache, dentry, filename, bi, len, mode);
213 pfs_cache_t *dirRemoveEntry(pfs_cache_t *clink, char *path)
215 pfs_dentry *dentry;
216 u32 size;
217 int i=0, val;
218 pfs_dentry *dlast=NULL, *dnext;
219 pfs_cache_t *c;
221 if ((c=getDentry(clink, path, &dentry, &size, 0))){
222 val=(int)dentry-(int)c->u.dentry;
223 if (val<0) val +=511;
224 val /=512; val *=512;
225 dnext=(pfs_dentry*)((int)c->u.dentry+val);
227 if (dnext==dentry){
228 if (dlast)
229 dlast->aLen=(dlast->aLen & FIO_S_IFMT) | ((dlast->aLen & 0xFFF) + (dnext->aLen & 0xFFF));
230 else{
231 dnext->pLen=dnext->inode=0;
233 if ((clink->u.inode->size) &&
234 (0>=dnext) && ((dnext==0) ||//strange?!?;
235 (size+(dnext->aLen & 0xFFF)>=clink->u.inode->size))) {
236 clink->u.inode->size -= dnext->aLen & 0xFFF;
239 return c;
241 i+=dnext->aLen & 0xFFF;
242 dlast=dnext;
243 (u32)dnext+=dnext->aLen & 0xFFF;
244 }while (i<512);
246 return NULL;
249 int checkDirForFiles(pfs_cache_t *clink)
251 pfs_dentry *dentry;
252 pfs_cache_t *dcache;
253 u32 size;
255 if((dcache=getDentry(clink, NULL, &dentry, &size, 2))){
256 cacheAdd(dcache);
257 return 0;
259 return 1;
262 void fillSelfAndParentDentries(pfs_cache_t *clink, pfs_blockinfo *self, pfs_blockinfo *parent)
264 pfs_dentry *dentry=clink->u.dentry;
266 memset(dentry, 0, metaSize);
267 dentry->inode=self->number;
268 *(u32*)dentry->path='.';
269 dentry->sub=self->subpart;
270 dentry->pLen=1;
271 dentry->aLen=12 | FIO_S_IFDIR;
273 (u32)dentry+=12;
275 dentry->inode=parent->number;
276 *(u32*)dentry->path=('.'<<8) + '.';
277 dentry->sub=parent->subpart;
278 dentry->pLen=2;
279 dentry->aLen=500 | FIO_S_IFDIR;
282 pfs_cache_t* setParent(pfs_cache_t *clink, pfs_blockinfo *bi, int *result)
284 int offset;
285 pfs_cache_t *dcache;
287 dcache=getDentriesAtPos(clink, 0, &offset, result);
288 if (dcache){
289 pfs_dentry *d=(pfs_dentry*)(12+(u32)dcache->u.data);
290 d->inode=bi->number;
291 d->sub =bi->subpart;
293 return dcache;