Suggestion from "mgh".
[open-ps2-loader.git] / modules / ps2fs / inode.c
blob71da63cb4a897361086c30a027a70eb11332c9b6
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: inode.c 911 2005-03-14 21:02:17Z oopo $
11 # PFS inode manipulation routines
14 #include "pfs.h"
16 ///////////////////////////////////////////////////////////////////////////////
17 // Globals
18 int blockSize=1;// block size(in sectors(512) )
21 ///////////////////////////////////////////////////////////////////////////////
22 // Function defenitions
25 void inodePrint(pfs_inode *inode)
27 dprintf("ps2fs: inodePrint: Checksum = 0x%lX, Magic = 0x%lX\n", inode->checksum, inode->magic);
28 dprintf("ps2fs: Mode = 0x%X, attr = 0x%X\n", inode->mode, inode->attr);
29 dprintf("ps2fs: size = 0x%08lX%08lX\n", (u32)(inode->size >> 32), (u32)(inode->size));
32 int inodeCheckSum(pfs_inode *inode)
34 u32 *ptr=(u32 *)inode;
35 u32 sum=0;
36 int i;
38 for(i=1; i < 256; i++)
39 sum+=ptr[i];
40 return sum;
43 pfs_cache_t *inodeGetData(pfs_mount_t *pfsMount, u16 sub, u32 inode, int *result)
45 return cacheGetData(pfsMount, sub, inode << pfsMount->inode_scale,
46 CACHE_FLAG_SEGD, result);
49 void inodeUpdateTime(pfs_cache_t *clink)
50 { // set the inode time's in cache
51 getPs2Time(&clink->u.inode->mtime);
52 memcpy(&clink->u.inode->ctime, &clink->u.inode->mtime, sizeof(pfs_datetime));
53 memcpy(&clink->u.inode->atime, &clink->u.inode->mtime, sizeof(pfs_datetime));
54 clink->flags|=CACHE_FLAG_DIRTY;
57 // Returns the cached inode for the file (dir) in the directory pointed
58 // to by the dir inode.
59 pfs_cache_t *inodeGetFileInDir(pfs_cache_t *dirInode, char *path, int *result)
61 pfs_dentry *dentry;
62 u32 size;
63 pfs_cache_t *clink;
65 if (path[0]==0)
66 return cacheUsedAdd(dirInode);
68 // If we're in the root dir, dont do anything for ".."
69 if ((dirInode->sector ==
70 dirInode->pfsMount->root_dir.number << dirInode->pfsMount->inode_scale) &&
71 (dirInode->sub == dirInode->pfsMount->root_dir.subpart) &&
72 (strcmp(path, "..") == 0))
73 return cacheUsedAdd(dirInode);
75 if ((*result=checkAccess(dirInode, 1)) < 0)
76 return NULL;
78 // Get dentry of file/dir specified by path from the dir pointed to
79 // by the inode (dirInode). Then return the cached inode for that dentry.
80 if ((clink=getDentry(dirInode, path, &dentry, &size, 0))){
81 cacheAdd(clink);
82 return inodeGetData(dirInode->pfsMount,
83 dentry->sub, dentry->inode, result);
86 *result=-ENOENT;
87 return NULL;
90 int inodeSync(pfs_blockpos_t *blockpos, u64 size, u32 used_segments)
92 int result=0;
93 u32 i;
94 u16 count;
96 for(i=blockSyncPos(blockpos, size); i; )
98 count=blockpos->inode->u.inode->data[fixIndex(blockpos->block_segment)].count;
100 i+=blockpos->block_offset;
102 if (i < count){
103 blockpos->block_offset=i;
104 break;
107 i-=count;
109 if (blockpos->block_segment + 1 == used_segments)
111 blockpos->block_offset=count;
112 if (i || blockpos->byte_offset){
113 printf("ps2fs: panic: fp exceeds file.\n");
114 return -EINVAL;
116 }else{
117 blockpos->block_offset=0;
118 blockpos->block_segment++;
121 if (fixIndex(blockpos->block_segment))
122 continue;
124 if ((blockpos->inode = blockGetNextSegment(blockpos->inode, &result)) == 0)
125 break;
127 i++;
130 return result;
133 pfs_cache_t *inodeGetFile(pfs_mount_t *pfsMount, pfs_cache_t *clink,
134 const char *name, int *result) {
135 char path[256];
136 pfs_cache_t *c;
138 c=inodeGetParent(pfsMount, clink, name, path, result);
139 if (c){
140 c=inodeGetFileInDir(c, path, result);
141 cacheAdd(c);
142 return c;
144 return NULL;
147 void inodeFill(pfs_cache_t *ci, pfs_blockinfo *bi, u16 mode, u16 uid, u16 gid)
149 u32 val;
151 memset(ci->u.inode, 0, metaSize);
153 ci->u.inode->magic=PFS_SEGD_MAGIC;
155 ci->u.inode->inode_block.number=bi->number;
156 ci->u.inode->inode_block.subpart=bi->subpart;
157 ci->u.inode->inode_block.count=bi->count;
159 ci->u.inode->last_segment.number=bi->number;
160 ci->u.inode->last_segment.subpart=bi->subpart;
161 ci->u.inode->last_segment.count=bi->count;
163 ci->u.inode->mode=mode;
164 ci->u.inode->uid=uid;
165 ci->u.inode->gid=gid;
167 if ((mode & FIO_S_IFMT) == FIO_S_IFDIR){
168 ci->u.inode->attr=0xA0;
169 ci->u.inode->size=sizeof(pfs_dentry);
170 val=2;
171 }else{
172 ci->u.inode->size=0;
173 val=1;
175 ci->u.inode->number_data=ci->u.inode->number_blocks=val;
178 getPs2Time(&ci->u.inode->ctime);
179 memcpy(&ci->u.inode->atime, &ci->u.inode->ctime, sizeof(pfs_datetime));
180 memcpy(&ci->u.inode->mtime, &ci->u.inode->ctime, sizeof(pfs_datetime));
182 ci->u.inode->number_segdesg=1;
183 ci->u.inode->data[0].number =bi->number;
184 ci->u.inode->data[0].subpart=bi->subpart;
185 ci->u.inode->data[0].count =bi->count;
187 ci->u.inode->subpart=bi->subpart;
189 ci->flags |= CACHE_FLAG_DIRTY;
193 // Given a path, this function will return the inode for the directory which holds
194 // the file (dir) specified by the filename.
196 // ie: if filename = /usr/local/ps2/games then it will return the inode for /usr/local/ps2
197 pfs_cache_t* inodeGetParent(pfs_mount_t *pfsMount, pfs_cache_t *clink, const char *filename,
198 char *path, int *result)
200 pfs_cache_t *link, *inode;
201 char *filename2=(char*)filename;
203 if (filename2[0]==0)
205 *result=-ENOENT;
206 if (clink) cacheAdd(clink);
207 return NULL;
210 if (filename2[0] == '/')
213 // Get inode for root dir
215 if (clink) cacheAdd(clink);
216 if ((clink=inodeGetData(pfsMount, pfsMount->root_dir.subpart,
217 pfsMount->root_dir.number, result))==0)
218 return NULL;
220 // dprintf("ps2fs: Got root dir inode!\n");
221 // inodePrint(clink->u.inode);
224 else if (clink==NULL)
227 // Otherwise if relative path, get inode for current dir
229 if ((clink=inodeGetData(pfsMount, pfsMount->current_dir.subpart,
230 pfsMount->current_dir.number, result))==0)
231 return NULL;
233 // dprintf("ps2fs: Got current dir inode!\n");
234 // inodePrint(clink->u.inode);
239 filename2=splitPath(filename2, path, result);
240 if (filename2==NULL) return NULL;
242 // If we've reached the end of the path, then we want to return
243 // the cached inode for the directory which holds the file/dir in path
244 if (filename2[0]==0)
246 if ((clink->u.inode->mode & FIO_S_IFMT) == FIO_S_IFDIR)
247 return clink;
249 cacheAdd(clink);
250 *result=-ENOTDIR; // not a directory
251 return NULL;
254 inode=inodeGetFileInDir(clink, path, result);
256 if (inode && ((inode->u.inode->mode & FIO_S_IFMT) == FIO_S_IFLNK))
258 if (symbolicLinks >= 4)
260 *result=-ELOOP; // too many symbolic links
261 cacheAdd(clink);
262 cacheAdd(inode);
263 return NULL;
266 symbolicLinks++;
267 link=inodeGetFile(pfsMount, clink, (char*)&inode->u.inode->data[1], result);
268 symbolicLinks--;
270 clink=inode;
271 if (link==0)
273 cacheAdd(inode);
274 return NULL;
276 inode=link;
278 cacheAdd(clink);
279 clink=inode;
281 } while (inode);
283 return NULL;
286 int inodeRemove(pfs_cache_t *parent, pfs_cache_t *inode, char *path)
288 pfs_cache_t *entry;
289 int rv=0;
291 if((entry=dirRemoveEntry(parent, path))!=NULL)
293 inodeUpdateTime(parent);
294 entry->flags|=CACHE_FLAG_DIRTY;
295 cacheAdd(entry);
297 else
298 rv=-ENOENT;
300 cacheAdd(parent);
301 if(rv==0)
303 inode->flags&=~CACHE_FLAG_DIRTY;
304 bitmapFreeInodeBlocks(inode);
305 if(parent->pfsMount->flags & FIO_ATTR_WRITEABLE)
306 cacheFlushAllDirty(parent->pfsMount);
309 cacheAdd(inode);
310 return rv;
313 pfs_cache_t *inodeCreateNewFile(pfs_cache_t *clink, u16 mode, u16 uid, u16 gid, int *result)
315 pfs_blockinfo a, b;
317 pfs_mount_t *pfsMount=clink->pfsMount;
318 u32 j;
319 u32 i;
320 pfs_cache_t *inode;
322 if ((mode & FIO_S_IFMT) == FIO_S_IFDIR)
324 if (pfsMount->num_subs > clink->u.inode->subpart)
325 clink->u.inode->subpart++;
326 else
327 clink->u.inode->subpart=0;
328 a.number =0;
329 a.subpart=clink->u.inode->subpart;
330 j= (pfsMount->zfree * (u64)100) / pfsMount->total_sector;
331 i= (pfsMount->free_zone[a.subpart] * (u64)100) /
332 (pfsMount->blockDev->getSize(pfsMount->fd, a.subpart) >> pfsMount->sector_scale);
333 if ((i < j) && ((j-i) >= 11))
334 a.subpart=getMaxthIndex(pfsMount);
335 }else{
336 a.number=clink->u.inode->inode_block.number;
337 a.subpart=clink->u.inode->inode_block.subpart;
338 a.count=clink->u.inode->inode_block.count;
340 a.count=1;
342 // Search for a free zone, starting from parent dir inode block
343 *result=searchFreeZone(pfsMount, &a, 2);
344 if (*result<0) return 0;
345 inode=cacheGetData(pfsMount, a.subpart, a.number << pfsMount->inode_scale,
346 CACHE_FLAG_SEGD | CACHE_FLAG_NOLOAD, result);
347 if (inode == NULL)
348 return NULL;
350 // Initialise the inode (which has been allocate blocks specified by a)
351 inodeFill(inode, (pfs_blockinfo*)&a, mode, uid, gid);
352 if ((mode & FIO_S_IFMT) != FIO_S_IFDIR)
353 return inode;
355 b.number=a.number;
356 b.subpart=a.subpart;
357 b.count=a.count;
359 *result=searchFreeZone(pfsMount, (pfs_blockinfo*)&a, 0);
360 if (*result<0){
361 cacheAdd(inode);
362 bitmapFreeBlockSegment(pfsMount, (pfs_blockinfo*)&b);
363 return NULL;
366 inode->u.inode->data[1].number=a.number;
367 inode->u.inode->data[1].subpart=a.subpart;
368 inode->u.inode->data[1].count =a.count;
370 return inode;