|
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 */
|