From: Adrian M. <zx8...@us...> - 2003-05-03 16:31:17
|
Update of /cvsroot/linuxdc/linux-sh-dc/fs/vmufs In directory sc8-pr-cvs1:/tmp/cvs-serv6932/fs/vmufs Modified Files: Tag: linux-sh-dc-2_4-branch inode.c super.c vmufs.h Log Message: Updated vmufs with more write support: BEWARE - experimental code Index: inode.c =================================================================== RCS file: /cvsroot/linuxdc/linux-sh-dc/fs/vmufs/Attic/inode.c,v retrieving revision 1.1.2.15 retrieving revision 1.1.2.16 diff -u -d -r1.1.2.15 -r1.1.2.16 --- inode.c 20 Nov 2002 22:53:00 -0000 1.1.2.15 +++ inode.c 3 May 2003 16:31:14 -0000 1.1.2.16 @@ -3,7 +3,7 @@ * * inode operations for the VMU file system * - * Copyright (C) 2002 Adrian McMenamin + * Copyright (C) 2002, 2003 Adrian McMenamin * Copyright (C) 2002 Paul Mundt * * This file is part of the LinuxDC project (linuxdc.sf.net). @@ -25,6 +25,10 @@ void *sbp = sb->u.generic_sbp; struct memcard *vmudetails = (struct memcard *) sbp; + if (dent->d_name.len > VMUFS_NAMELEN) + return (ERR_PTR(-ENAMETOOLONG)); + + long blck_read = vmudetails->dir_bnum; struct buffer_head *bh = bread(sb->s_dev, blck_read, 512); struct vmufs_file_info *first_one = NULL; @@ -32,6 +36,7 @@ int fno = 0; do { + /* Build a list of files in the directory */ struct vmufs_file_info *saved_file = kmalloc(sizeof(struct vmufs_file_info), GFP_KERNEL); saved_file->prev = last_one; @@ -75,6 +80,8 @@ if (first_one == NULL) { error = -ENOENT; + dent->d_inode = NULL; + /* No files at all */ return ERR_PTR(error); } if (memcmp(dent->d_name.name, first_one->fname, 12) != 0) { @@ -83,11 +90,17 @@ kfree(first_one->prev); } else { kfree(first_one); + dent->d_inode = NULL; + d_add(dent, NULL); error = -ENOENT; return ERR_PTR(error); } } else { ino = iget(sb, le16_to_cpu(first_one->fblk)); + if (!ino) { + error = -EACCES; + return (ERR_PTR(error)); + } break; } } while (1); @@ -120,11 +133,177 @@ return 0; } +static int vmufs_inode_create(struct inode *dir, struct dentry *de, + int imode) +{ + /* Create an inode */ + if (de->d_name.len > VMUFS_NAMELEN) + return (ERR_PTR(-ENAMETOOLONG)); + + int y; + struct inode *inode; + struct super_block *sb = dir->i_sb; + void *sbp = sb->u.generic_sbp; + struct memcard *vmudetails = (struct memcard *) sbp; + struct buffer_head *bh_fat, *bh; + __u16 fatdata; + + inode = new_inode(sb); + if (!inode) { + return -ENOSPC; + } + /* Walk through blocks looking for a new inode */ + + /* Is this an executible file? */ + if (imode & 73) { /*Octal 111 */ + inode->i_ino = 0; + /* But this already allocated? */ + bh_fat = + bread(sb->s_dev, vmudetails->fat_bnum, + sb->s_blocksize); + fatdata = ((__u16 *) bh_fat->b_data)[0]; + if (fatdata != 0xfffc) { + printk(KERN_ERR + "vmufs: cannot write executible file to vmu - block 0 already allocated.\n"); + brelse(bh_fat); + return -ENOSPC; + } + + } else { + /*Look for a free block in the FAT */ + + long nextblock = 199; /*TO DO: Make this portable */ + bh_fat = + bread(sb->s_dev, vmudetails->fat_bnum, + sb->s_blocksize); + do { + fatdata = ((__u16 *) bh_fat->b_data)[nextblock]; + if (fatdata == 0xfffc) + break; /*empty block */ + if (--nextblock < 0) + break; + } while (1); + if (nextblock < 0) { + iput(inode); + brelse(bh_fat); + return -ENOSPC; + } + inode->i_ino = nextblock; + } + brelse(bh_fat); + + + + + inode->i_uid = current->fsuid; + inode->i_gid = + (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blksize = sb->s_blocksize; + inode->i_mode = imode; + inode->i_blocks = 0; + inode->i_sb = sb; + insert_inode_hash(inode); + mark_inode_dirty(inode); + inode->i_op = &vmufs_inode_operations; + inode->i_fop = &vmufs_file_operations; + + /* Write to the directory */ + /* Now search for space for the directory entry */ + long blck_read = vmudetails->dir_bnum; + bh = bread(sb->s_dev, blck_read, inode->i_blksize); + + for (y = 0; y < (vmudetails->dir_len * 0x10); y++) { + if ((y / 0x10) > (vmudetails->dir_bnum - blck_read)) { + brelse(bh); + blck_read--; + bh = bread(sb->s_dev, blck_read, inode->i_blksize); + } + if (((bh->b_data)[(y % 0x10) * 0x20]) == 0) + break; + } + /* Have the directory entry + * so now update it */ + int z = (y % 0x10) * 0x20; + if (inode->i_ino != 0) + bh->b_data[z] = 0x33; /* data file */ + else + bh->b_data[z] = 0xcc; + if ((bh->b_data[z + 1] != (char) 0x00) + && (bh->b_data[z + 1] != (char) 0xff)) + bh->b_data[z + 1] = (char) 0x00; + ((__u16 *) bh->b_data)[z / 2 + 1] = cpu_to_le16(inode->i_ino); + /* Name */ + memset((char *) (bh->b_data + z + 0x04), '\0', 0x0C); + memcpy((char *) (bh->b_data + z + 0x04), ((de->d_name).name), + de->d_name.len); + /* BCD timestamp it */ + unsigned long unix_date = CURRENT_TIME; + int year, day, nl_day, month; /*inspired by FAT driver */ + day = unix_date / 86400 - 3652; + year = day / 365; + if ((year + 3) / 4 + 365 * year > day) + year--; + day -= (year + 3) / 4 + 365 * year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } else { + nl_day = (year & 3) || day <= 59 ? day : day - 1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) + break; + } + + __u8 century = 19; + if (year > 19) + century = 20; + bh->b_data[z + 0x10] = bcd_from_u8(century); + __u8 u8year = year + 80; + if (u8year > 99) + u8year = u8year - 100; + bh->b_data[z + 0x11] = bcd_from_u8(u8year); + bh->b_data[z + 0x12] = bcd_from_u8((__u8) month); + bh->b_data[z + 0x13] = + bcd_from_u8((__u8) day - day_n[month - 1] + 1); + bh->b_data[z + 0x14] = + bcd_from_u8((__u8) ((unix_date / 3600) % 24)); + bh->b_data[z + 0x15] = bcd_from_u8((__u8) ((unix_date / 60) % 60)); + bh->b_data[z + 0x16] = bcd_from_u8((__u8) (unix_date % 60)); + + ((__u16 *) bh->b_data)[z / 2 + 0x0C] = + cpu_to_le16(inode->i_blocks); + if (inode->i_ino != 0) + ((__u16 *) bh->b_data)[z / 2 + 0x0D] = 0; + else + ((__u16 *) bh->b_data)[z / 2 + 0x0D] = 1; /*game */ + inode->i_mtime = unix_date; + mark_buffer_dirty(bh); + brelse(bh); + + + d_instantiate(de, inode); + + + + return 0; +} + + +static int vmufs_inode_rename(struct inode *in_source, + struct dentry *de_source, + struct inode *in_target, + struct dentry *de_target) +{ + return -EPERM; +} struct inode_operations vmufs_inode_operations = { lookup:vmufs_inode_lookup, unlink:vmufs_inode_unlink, + create:vmufs_inode_create, + rename:vmufs_inode_rename, }; @@ -212,7 +391,175 @@ fsync:file_fsync, }; -ssize_t vmufs_file_read(struct file *file, char *buf, size_t count, + +int vmufs_game_write(struct file *file, const char *buf, char *writebuf, + size_t count) +{ + /* Assume this is a game */ + return -EIO; +} + +ssize_t vmufs_file_write(struct file * file, const char *buf, size_t count, + loff_t * ppos) +{ + struct buffer_head *bh; + struct buffer_head *bh_fat; + if ((ssize_t) count < 0) + return -ENOENT; + struct inode *in = (file->f_dentry)->d_inode; + struct super_block *sb = in->i_sb; + struct memcard *vmudetails = + ((struct memcard *) sb->u.generic_sbp); + + + unsigned long blkoffset = *ppos >> in->i_sb->s_blocksize_bits; + unsigned long blksize = in->i_blksize; + + /* We will assume that all files - + * unless having inode value of 0 + * are data files + */ + + + /* copy buffer */ + char *writebuf; + if (count > in->i_blksize) + count = in->i_blksize; + writebuf = kmalloc(count, GFP_KERNEL); + copy_from_user(writebuf, buf, count); + + + if (in->i_ino == 0) { + vmufs_game_write(file, buf, writebuf, count); + } else { + + /* We have a data file - + * so let's write it out to + * the vmu */ + + /*Start by writing out to first block */ + if (blkoffset == 0) { + unsigned long currentblock = in->i_ino; + __u16 fatdata; + bh = bread(sb->s_dev, in->i_ino, in->i_blksize); + if (count < in->i_blksize) + memset((char *) (bh->b_data), '\0', + in->i_blksize); + memcpy((char *) (bh->b_data), writebuf, count); + mark_buffer_dirty(bh); + brelse(bh); + in->i_size = in->i_blksize; /* will increment as we grow */ + in->i_blocks = 1; + /* Update FAT */ + bh_fat = + bread(in->i_sb->s_dev, vmudetails->fat_bnum, + blksize); + /*Wipe out any old FAT records for this inode */ + do { + fatdata = + ((__u16 *) bh_fat-> + b_data)[(__u16) currentblock]; + if (fatdata == 0xfffc) + break; /* already empty */ + ((__u16 *) (bh_fat-> + b_data))[(__u16) currentblock] + = 0xfffc; + mark_buffer_dirty(bh_fat); + if (fatdata == 0xfffa) + break; /* end of file */ + } while (1); + /* Avoid writes to mtd if possible + * so check if a write is really + * required here */ + fatdata = + ((__u16 *) bh_fat-> + b_data)[(__u16) (in->i_ino)]; + if (fatdata != 0xfffa) { + ((__u16 *) (bh_fat->b_data))[(__u16) (in-> + i_ino)] + = 0xfffa; + mark_buffer_dirty(bh_fat); + } + brelse(bh_fat); + + } + /* Now every other block */ + else { + /*Look for a free block in the FAT */ + __u16 fatdata; + unsigned long nextblock = in->i_ino - 1; + bh_fat = + bread(in->i_sb->s_dev, vmudetails->fat_bnum, + blksize); + do { + fatdata = + ((__u16 *) bh_fat->b_data)[nextblock]; + if (fatdata == 0xfffc) + break; /*empty block */ + if (--nextblock < 0) + break; + } while (1); + if ((long) nextblock < 0) { + brelse(bh_fat); + kfree(writebuf); + printk(KERN_ERR + "vmufs: Out of space on vmu device\n"); + return -EFBIG; + } + /*Now we have the space - write the block out */ + bh = bread(sb->s_dev, nextblock, in->i_blksize); + if (count < in->i_blksize) + memset((char *) (bh->b_data), '\0', + in->i_blksize); + memcpy((char *) (bh->b_data), writebuf, count); + mark_buffer_dirty(bh); + brelse(bh); + in->i_size += in->i_blksize; + in->i_blocks++; + /*Now update the FAT if required */ + fatdata = + ((__u16 *) bh_fat->b_data)[(__u16) nextblock]; + if (fatdata != 0xfffa) { + ((__u16 *) (bh_fat-> + b_data))[(__u16) nextblock] = + 0xfffa; + mark_buffer_dirty(bh_fat); + } + int previousblock = in->i_ino; + do { + fatdata = + ((__u16 *) bh_fat-> + b_data)[previousblock]; + if ((fatdata == 0xfffc) + || (fatdata == 0xfffa)) { + ((__u16 *) bh_fat-> + b_data)[previousblock] = + nextblock; + mark_buffer_dirty(bh_fat); + break; + } + previousblock = fatdata; + blkoffset--; + } while (blkoffset > 0); + brelse(bh_fat); + if (blkoffset < 1) { + /* Additional sanity check */ + kfree(writebuf); + return -EIO; + } + + } + + + } + + + kfree(writebuf); + *ppos += count; + return count; +} + +ssize_t vmufs_file_read(struct file * file, char *buf, size_t count, loff_t * ppos) { struct inode *in = file->f_dentry->d_inode; @@ -254,6 +601,7 @@ memcpy(readbuf + x * blksize, bh_file->b_data, blksize); x++; fatblk = ((__u16 *) bh_fat->b_data)[next_block]; + brelse(bh_file); if (fatblk == 0xfffa) break; next_block = fatblk; @@ -264,12 +612,19 @@ copy_to_user(buf, readbuf, count); kfree(readbuf); *ppos += count; - + brelse(bh_fat); return count; } +static int vmufs_file_open(struct inode *in, struct file *f) +{ + return 0; +} + struct file_operations vmufs_file_operations = { read:vmufs_file_read, + write:vmufs_file_write, + open:vmufs_file_open, }; struct inode_operations vmufs_file_inode_operations = { Index: super.c =================================================================== RCS file: /cvsroot/linuxdc/linux-sh-dc/fs/vmufs/Attic/super.c,v retrieving revision 1.1.2.14 retrieving revision 1.1.2.15 diff -u -d -r1.1.2.14 -r1.1.2.15 --- super.c 20 Nov 2002 22:53:00 -0000 1.1.2.14 +++ super.c 3 May 2003 16:31:14 -0000 1.1.2.15 @@ -7,7 +7,7 @@ * http://linuxdc.org * * http://sourceforge.net/projects/linuxdc * * * - * This software is copyright, 2002, * + * This software is copyright, 2002, 2003 * * Adrian McMenamin * * ad...@mc... * * * @@ -39,6 +39,13 @@ return (topnib * 10) + botnib; } +inline __u8 bcd_from_u8(__u8 num) +{ + __u8 topnib = num / 10; + __u8 botnib = num % 10; + return ((topnib << 4) | (botnib)); +} + static struct super_block *vmufs_read_super(struct super_block *, void *, int); @@ -227,12 +234,12 @@ * Have to wander through this * to find the appropriate entry */ blck_read = vmudetails->dir_bnum; - bh = bread(sb->s_dev, blck_read, 512); + bh = bread(sb->s_dev, blck_read, in->i_blksize); for (y = 0; y < (vmudetails->dir_len * 0x10); y++) { if ((y / 0x10) > (vmudetails->dir_bnum - blck_read)) { brelse(bh); blck_read--; - bh = bread(sb->s_dev, blck_read, 512); + bh = bread(sb->s_dev, blck_read, in->i_blksize); } if (le16_to_cpu (((__u16 *) bh->b_data)[(y % 0x10) * 0x10 + @@ -251,7 +258,7 @@ if ((y / 0x10) > (vmudetails->dir_bnum - blck_read)) { brelse(bh); blck_read--; - bh = bread(sb->s_dev, blck_read, 512); + bh = bread(sb->s_dev, blck_read, in->i_blksize); } if (bh->b_data[(y % 0x10) * 0x20] == 0x00) { /* Not a file */ y--; @@ -260,10 +267,12 @@ brelse(bh); /* force read of correct block */ bh = bread(sb->s_dev, - (vmudetails->dir_bnum - y / 0x10), 512); + (vmudetails->dir_bnum - y / 0x10), + in->i_blksize); bh_old = bread(sb->s_dev, - (vmudetails->dir_bnum - x / 0x10), 512); + (vmudetails->dir_bnum - x / 0x10), + in->i_blksize); /* Copy this directory entry over */ for (z = 0; z < 0x10; z++) { ((__u16 *) bh_old->b_data)[(x % 0x10) * @@ -288,12 +297,94 @@ static void vmufs_write_inode(struct inode *in) { - /* Nothing at present */ + struct buffer_head *bh; + int y, blck_read, name_len; + struct super_block *sb = in->i_sb; + struct memcard *vmudetails = + ((struct memcard *) sb->u.generic_sbp); -} static struct super_operations vmufs_super_operations = { - read_inode:vmufs_read_inode, write_inode:vmufs_write_inode, - delete_inode:vmufs_delete_inode, put_super:vmufs_put_super, + printk(KERN_INFO "In vmufs_write_inode\n"); + + /* update the directory and inode details */ + + + /* Now search for the directory entry */ + blck_read = vmudetails->dir_bnum; + bh = bread(sb->s_dev, blck_read, in->i_blksize); + for (y = 0; y < (vmudetails->dir_len * 0x10); y++) { + if ((y / 0x10) > (vmudetails->dir_bnum - blck_read)) { + brelse(bh); + blck_read--; + bh = bread(sb->s_dev, blck_read, in->i_blksize); + } + if (le16_to_cpu + (((__u16 *) bh->b_data)[(y % 0x10) * 0x10 + + 0x01]) == in->i_ino) + break; + } + /* Have the directory entry + * so now update it */ + int z = (y % 0x10) * 0x20; + if (in->i_ino != 0) + bh->b_data[z] = 0x33; /* data file */ + else + bh->b_data[z] = 0xcc; + if ((bh->b_data[z + 1] != (char) 0x00) + && (bh->b_data[z + 1] != (char) 0xff)) + bh->b_data[z + 1] = (char) 0x00; + ((__u16 *) bh->b_data)[z / 2 + 1] = cpu_to_le16(in->i_ino); + /* BCD timestamp it */ + unsigned long unix_date = CURRENT_TIME; + int year, day, nl_day, month; /*inspired by FAT driver */ + day = unix_date / 86400 - 3652; + year = day / 365; + if ((year + 3) / 4 + 365 * year > day) + year--; + day -= (year + 3) / 4 + 365 * year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } else { + nl_day = (year & 3) || day <= 59 ? day : day - 1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) + break; + } + + __u8 century = 19; + if (year > 19) + century = 20; + bh->b_data[z + 0x10] = bcd_from_u8(century); + __u8 u8year = year + 80; + if (u8year > 99) + u8year = u8year - 100; + bh->b_data[z + 0x11] = bcd_from_u8(u8year); + bh->b_data[z + 0x12] = bcd_from_u8((__u8) month); + bh->b_data[z + 0x13] = + bcd_from_u8((__u8) day - day_n[month - 1] + 1); + bh->b_data[z + 0x14] = + bcd_from_u8((__u8) ((unix_date / 3600) % 24)); + bh->b_data[z + 0x15] = bcd_from_u8((__u8) ((unix_date / 60) % 60)); + bh->b_data[z + 0x16] = bcd_from_u8((__u8) (unix_date % 60)); + + ((__u16 *) bh->b_data)[z / 2 + 0x0C] = cpu_to_le16(in->i_blocks); + if (in->i_ino != 0) + ((__u16 *) bh->b_data)[z / 2 + 0x0D] = 0; + else + ((__u16 *) bh->b_data)[z / 2 + 0x0D] = 1; /*game */ + in->i_mtime = unix_date; + mark_buffer_dirty(bh); + brelse(bh); + +} + +static struct super_operations vmufs_super_operations = { + + read_inode:vmufs_read_inode, + write_inode:vmufs_write_inode, + delete_inode:vmufs_delete_inode, + put_super:vmufs_put_super, statfs:vmufs_statfs, }; @@ -370,7 +461,7 @@ root_i = iget(sb, vmudata->sb_bnum); if (!root_i) { - printk("VMUFS: get root inode failed\n"); + printk(KERN_ERR "vmufs: get root inode failed\n"); return NULL; } Index: vmufs.h =================================================================== RCS file: /cvsroot/linuxdc/linux-sh-dc/fs/vmufs/Attic/vmufs.h,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -u -d -r1.1.2.3 -r1.1.2.4 --- vmufs.h 10 Nov 2002 00:52:00 -0000 1.1.2.3 +++ vmufs.h 3 May 2003 16:31:14 -0000 1.1.2.4 @@ -3,9 +3,12 @@ *****************************/ /* Licenced under the GPL v2 - * Copyright Adrian McMenamin, 2002 + * Copyright Adrian McMenamin, 2002, 2003 * ad...@mc... */ + +#define VMUFS_NAMELEN 12 + extern struct inode_operations vmufs_inode_operations; extern struct inode_operations vmufs_file_inode_operations; extern struct file_operations vmufs_file_dir_operations; @@ -36,3 +39,10 @@ inline int int_from_bcd(__u8 bcd); +inline __u8 bcd_from_u8(__u8 num); + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ |