Suggestion from "mgh".
[open-ps2-loader.git] / modules / ps2fs / super.c
blobc8d060accfdad8a1bef4414200809d933153ed86
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: super.c 911 2005-03-14 21:02:17Z oopo $
11 # PFS superblock manipulation routines
14 #include "pfs.h"
16 int checkZoneSize(u32 zone_size)
18 if((zone_size & (zone_size - 1)) || (zone_size < (2 * 1024)) || (zone_size > (128 * 1024)))
20 printf("ps2fs: Error: Invalid zone size\n");
21 return 0;
24 return 1;
27 // Returns the number of sectors (512 byte units) which will be used
28 // for bitmaps, given the zone size and partition size
29 u32 getBitmapSectors(int zoneScale, u32 partSize)
31 int w, zones = partSize / (1 << zoneScale);
33 w = (zones & 7);
34 zones = zones / 8 + w;
36 w = (zones & 511);
37 return zones / 512 + w;
40 // Returns the number of blocks/zones which will be used for bitmaps
41 u32 getBitmapBocks(int scale, u32 mainsize)
43 u32 a=getBitmapSectors(scale, mainsize);
44 return a / (1<<scale) + ((a % (1<<scale))>0);
47 // Formats a partition (main or sub) by filling with fragment pattern and setting the bitmap accordingly
48 int formatSub(block_device *blockDev, int fd, u32 sub, u32 reserved, u32 scale, u32 fragment)
50 pfs_cache_t *cache;
51 int i;
52 u32 sector, count, size, *b;
53 int result = 0;
55 size = blockDev->getSize(fd, sub);
56 sector = 1 << scale;
57 count = getBitmapSectors(scale, size);
58 if (reserved>=2)
59 sector+=0x2000;
60 reserved += getBitmapBocks(scale, size);
62 if((cache = cacheAllocClean(&result)))
64 // fill with fragment pattern
65 for (i=127; i>=0; i--)
66 cache->u.bitmap[i]=fragment;
68 // set as allocated the sectors up to reserved, for the first part of the bitmap
69 // this will mark the area the bitmaps themselves occupy as used
70 for (i=0, b=cache->u.bitmap; i<reserved; i++)
72 if (i && ((i & 0x1F)==0))
73 b++;
74 *b |= 1 << (i & 0x1F);
77 dprintf("ps2fs: Format sub: sub = %ld, sector start = %ld, ", sub, sector);
79 // set the rest of the bitmap to the fragment
80 while (count-- && ((result=blockDev->transfer(fd, cache->u.bitmap, sub, sector++, 1, 1))>=0))
81 for (i=127; i>=0; i--)
82 cache->u.bitmap[i]=fragment;
84 dprintf("sector end = %ld\n", sector - 1);
86 cacheAdd(cache);
88 return result;
91 // Formats a partition and all sub-partitions with PFS
92 int _format(block_device *blockDev, int fd, int zonesize, int fragment)
94 int result, result2;
95 pfs_cache_t *clink, *cache;
96 pfs_super_block *sb;
97 int scale;
98 u32 i, mainsize, subnumber = blockDev->getSubNumber(fd);
100 mainsize=blockDev->getSize(fd, 0);
101 if(checkZoneSize(zonesize) == 0)
102 return -EINVAL;
104 scale = getScale(zonesize, 512);
106 if((clink=cacheAllocClean(&result)))
108 sb = clink->u.superblock;
109 memset(sb, 0, metaSize);
110 sb->magic = PFS_SUPER_MAGIC;
111 sb->version = 3;
112 sb->unknown1 = 0x201;
113 sb->zone_size = zonesize;
114 sb->num_subs = subnumber;
115 sb->log.number = getBitmapBocks(scale, mainsize) + (0x2000 >> scale) + 1;
116 sb->log.count = 0x20000 / zonesize ? 0x20000 / zonesize : 1;
118 dprintf("ps2fs: Format: log.number = %ld, log.count = %d\n", sb->log.number << scale, sb->log.count);
120 sb->root.count = 1;
121 sb->root.number = sb->log.number + sb->log.count;
122 if((result = journalResetThis(blockDev, fd, sb->log.number<<scale)) >= 0)
124 if((cache = cacheAllocClean(&result2)))
126 fillSelfAndParentDentries(cache, &sb->root, &sb->root);
127 result2 = blockDev->transfer(fd, cache->u.dentry, 0, (sb->root.number+1) << scale,
128 1 << blockSize, 1);
129 if(result2 == 0)
131 // setup root directory
132 inodeFill(cache, &sb->root, 0x11FF, 0, 0);
133 cache->u.inode->data[1].subpart = 0;
134 cache->u.inode->data[1].number = sb->root.number + 1;
135 cache->u.inode->data[1].count = 1;
136 cache->u.inode->checksum = inodeCheckSum(cache->u.inode);
138 result2=blockDev->transfer(fd, cache->u.inode, 0, sb->root.number << scale,
139 1 << blockSize, 1);
142 cacheAdd(cache);
145 if((result = result2) >= 0)
147 for (i=0; i < subnumber+1; i++)
148 if((result=formatSub(blockDev, fd, i, i ? 1 : (0x2000 >> scale) +
149 sb->log.count*8, scale, fragment))<0)
150 break;
152 if((result == 0) && ((result = blockDev->transfer(fd, sb, 0, PFS_SUPER_BACKUP_SECTOR, 1, 1))==0))
153 result = blockDev->transfer(fd, sb, 0, PFS_SUPER_SECTOR, 1, 1);
157 cacheAdd(clink);
158 blockDev->flushCache(fd);
160 return result;
163 // Formats sub partitions which are added to the main partition after it is initially
164 // formatted with PFS
165 int updateSuperBlock(pfs_mount_t *pfsMount, pfs_super_block *superblock, u32 sub)
167 u32 scale;
168 u32 i;
169 u32 count;
170 int rv;
172 scale = getScale(superblock->zone_size, 512);
173 count = superblock->num_subs + sub + 1;
175 for(i = superblock->num_subs + 1; i < count; i++)
177 rv = formatSub(pfsMount->blockDev, pfsMount->fd, i, 1, scale, 0);
178 if(rv < 0)
179 return rv;
182 superblock->num_subs = sub;
184 // Write superblock, then write backup
185 rv = pfsMount->blockDev->transfer(pfsMount->fd, superblock, 0, PFS_SUPER_SECTOR, 1, IOCTL2_TMODE_WRITE);
186 if(!rv)
187 rv = pfsMount->blockDev->transfer(pfsMount->fd, superblock, 0, PFS_SUPER_BACKUP_SECTOR, 1, IOCTL2_TMODE_WRITE);
189 pfsMount->blockDev->flushCache(pfsMount->fd);
191 return rv;
194 int mountSuperBlock(pfs_mount_t *pfsMount)
196 int result;
197 pfs_cache_t *clink;
198 pfs_super_block *superblock;
199 u32 sub;
200 u32 i;
203 // Get number of sub partitions attached to the main partition
204 sub = pfsMount->blockDev->getSubNumber(pfsMount->fd);
206 // Allocate a cache entry for the superblock
207 clink = cacheAllocClean(&result);
208 if(!clink)
209 return result;
211 superblock = clink->u.superblock;
213 // Read the suprerblock from the main partition
214 result = pfsMount->blockDev->transfer(pfsMount->fd, superblock, 0, PFS_SUPER_SECTOR, 1, IOCTL2_TMODE_READ);
215 if(result) goto error;
217 if((superblock->magic != PFS_SUPER_MAGIC) || (superblock->version >= PFS_VERSION))
219 printf("ps2fs: Error: Invalid magic/version\n");
220 cacheAdd(clink);
221 return -EIO;
224 if(!checkZoneSize(superblock->zone_size))
225 result = -EIO;
227 if((superblock->fsckStat & FSCK_STAT_WRITE_ERROR) && (pfsMount->flags & FIO_ATTR_EXECUTABLE))
228 result = -EIO;
230 if(sub < superblock->num_subs)
232 printf("ps2fs: Error: Filesystem larger than partition\n");
233 result = -EIO;
236 if(result) goto error;
238 // If new subs have been added, update filesystem
239 if(superblock->num_subs < sub)
241 dprintf("ps2fs: New subs added, updating filesystem..\n");
242 result = updateSuperBlock(pfsMount, superblock, sub);
245 if(result) goto error;
247 pfsMount->zsize = superblock->zone_size;
248 pfsMount->sector_scale = getScale(pfsMount->zsize, 512);
249 pfsMount->inode_scale = getScale(pfsMount->zsize, metaSize);
250 pfsMount->num_subs = superblock->num_subs;
251 memcpy(&pfsMount->root_dir, &superblock->root, sizeof(pfs_blockinfo));
252 memcpy(&pfsMount->log, &superblock->log, sizeof(pfs_blockinfo));
253 memcpy(&pfsMount->current_dir, &superblock->root, sizeof(pfs_blockinfo));
254 pfsMount->total_sector = 0;
255 pfsMount->uid = 0;
256 pfsMount->gid = 0;
258 // Do a journal restore (in case of un-clean unmount)
259 journalResetore(pfsMount);
261 // Calculate free space and total size
262 for(i = 0; i < (pfsMount->num_subs + 1); i++)
264 int free;
266 pfsMount->total_sector += pfsMount->blockDev->getSize(pfsMount->fd, i) >> pfsMount->sector_scale;
268 free = calcFreeZones(pfsMount, i);
269 pfsMount->free_zone[i] = free;
270 pfsMount->zfree += free;
273 error:
274 cacheAdd(clink);
275 return result;