summaryrefslogtreecommitdiffstats
path: root/fs/adfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/adfs/inode.c')
-rw-r--r--fs/adfs/inode.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
new file mode 100644
index 000000000..37daaa3c3
--- /dev/null
+++ b/fs/adfs/inode.c
@@ -0,0 +1,216 @@
+/*
+ * linux/fs/adfs/inode.c
+ *
+ * Copyright (C) 1997 Russell King
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/adfs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+
+/*
+ * Old Inode numbers:
+ * bit 30 - 16 FragID of parent object
+ * bit 15 0 1
+ * bit 14 - 0 FragID of object Offset into parent FragID
+ *
+ * New Inode numbers:
+ * Inode = Frag ID of parent (14) + Frag Offset (8) + (index into directory + 1)(8)
+ */
+#define inode_frag(ino) ((ino) >> 8)
+#define inode_idx(ino) ((ino) & 0xff)
+#define inode_dirindex(idx) (((idx) & 0xff) * 26 - 21)
+
+#define frag_id(x) (((x) >> 8) & 0x7fff)
+#define off(x) (((x) & 0xff) ? ((x) & 0xff) - 1 : 0)
+
+static inline int adfs_inode_validate_no (struct super_block *sb, unsigned int inode_no)
+{
+ unsigned long max_frag_id;
+
+ max_frag_id = sb->u.adfs_sb.s_map_size * sb->u.adfs_sb.s_ids_per_zone;
+
+ return (inode_no & 0x800000ff) ||
+ (frag_id (inode_frag (inode_no)) > max_frag_id) ||
+ (frag_id (inode_frag (inode_no)) < 2);
+}
+
+int adfs_inode_validate (struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+
+ return adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00) ||
+ adfs_inode_validate_no (sb, inode->u.adfs_i.file_id << 8);
+}
+
+unsigned long adfs_inode_generate (unsigned long parent_id, int diridx)
+{
+ if (!parent_id)
+ return -1;
+
+ if (diridx)
+ diridx = (diridx + 21) / 26;
+
+ return (parent_id << 8) | diridx;
+}
+
+unsigned long adfs_inode_objid (struct inode *inode)
+{
+ if (adfs_inode_validate (inode)) {
+ adfs_error (inode->i_sb, "adfs_inode_objid",
+ "bad inode number: %lu (%X,%X)",
+ inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
+ return 0;
+ }
+
+ return inode->u.adfs_i.file_id;
+}
+
+int adfs_bmap (struct inode *inode, int block)
+{
+ struct super_block *sb = inode->i_sb;
+ unsigned int blk;
+
+ if (adfs_inode_validate (inode)) {
+ adfs_error (sb, "adfs_bmap",
+ "bad inode number: %lu (%X,%X)",
+ inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
+ return 0;
+ }
+
+ if (frag_id(inode->u.adfs_i.file_id) == ADFS_ROOT_FRAG)
+ blk = sb->u.adfs_sb.s_map_block + off(inode_frag (inode->i_ino)) + block;
+ else
+ blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id),
+ off (inode->u.adfs_i.file_id) + block);
+ return blk;
+}
+
+unsigned int adfs_parent_bmap (struct inode *inode, int block)
+{
+ struct super_block *sb = inode->i_sb;
+ unsigned int blk, fragment;
+
+ if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
+ adfs_error (sb, "adfs_parent_bmap",
+ "bad inode number: %lu (%X,%X)",
+ inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
+ return 0;
+ }
+
+ fragment = inode_frag (inode->i_ino);
+ if (frag_id (fragment) == ADFS_ROOT_FRAG)
+ blk = sb->u.adfs_sb.s_map_block + off (fragment) + block;
+ else
+ blk = adfs_map_lookup (sb, frag_id (fragment), off (fragment) + block);
+ return blk;
+}
+
+static int adfs_atts2mode (unsigned char mode, unsigned int filetype)
+{
+ int omode = 0;
+
+ if (filetype == 0xfc0 /* LinkFS */) {
+ omode = S_IFLNK|S_IRUSR|S_IWUSR|S_IXUSR|
+ S_IRGRP|S_IWGRP|S_IXGRP|
+ S_IROTH|S_IWOTH|S_IXOTH;
+ } else {
+ if (mode & ADFS_NDA_DIRECTORY)
+ omode |= S_IFDIR|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH;
+ else
+ omode |= S_IFREG;
+ if (mode & ADFS_NDA_OWNER_READ) {
+ omode |= S_IRUSR;
+ if (filetype == 0xfe6 /* UnixExec */)
+ omode |= S_IXUSR;
+ }
+ if (mode & ADFS_NDA_OWNER_WRITE)
+ omode |= S_IWUSR;
+ if (mode & ADFS_NDA_PUBLIC_READ) {
+ omode |= S_IRGRP | S_IROTH;
+ if (filetype == 0xfe6)
+ omode |= S_IXGRP | S_IXOTH;
+ }
+ if (mode & ADFS_NDA_PUBLIC_WRITE)
+ omode |= S_IWGRP | S_IWOTH;
+ }
+ return omode;
+}
+
+void adfs_read_inode (struct inode *inode)
+{
+ struct super_block *sb;
+ struct buffer_head *bh[4];
+ struct adfs_idir_entry ide;
+ int buffers;
+
+ sb = inode->i_sb;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_version = ++event;
+
+ if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
+ adfs_error (sb, "adfs_read_inode",
+ "bad inode number: %lu", inode->i_ino);
+ goto bad;
+ }
+
+ if (frag_id(inode_frag (inode->i_ino)) == ADFS_ROOT_FRAG &&
+ inode_idx (inode->i_ino) == 0) {
+ /* root dir */
+ inode->i_mode = S_IRWXUGO | S_IFDIR;
+ inode->i_nlink = 2;
+ inode->i_size = ADFS_NEWDIR_SIZE;
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = inode->i_size / sb->s_blocksize;
+ inode->i_mtime =
+ inode->i_atime =
+ inode->i_ctime = 0;
+ inode->u.adfs_i.file_id = inode_frag (inode->i_ino);
+ } else {
+ if (!(buffers = adfs_dir_read_parent (inode, bh)))
+ goto bad;
+
+ if (adfs_dir_check (inode, bh, buffers, NULL)) {
+ adfs_dir_free (bh, buffers);
+ goto bad;
+ }
+
+ if (!adfs_dir_find_entry (sb, bh, buffers, inode_dirindex (inode->i_ino), &ide)) {
+ adfs_dir_free (bh, buffers);
+ goto bad;
+ }
+ adfs_dir_free (bh, buffers);
+ inode->i_mode = adfs_atts2mode (ide.mode, ide.filetype);
+ inode->i_nlink = 2;
+ inode->i_size = ide.size;
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ inode->i_mtime =
+ inode->i_atime =
+ inode->i_ctime = ide.mtime;
+ inode->u.adfs_i.file_id = ide.file_id;
+ }
+
+ if (S_ISDIR(inode->i_mode))
+ inode->i_op = &adfs_dir_inode_operations;
+ else if (S_ISREG(inode->i_mode))
+ inode->i_op = &adfs_file_inode_operations;
+ return;
+
+bad:
+ inode->i_mode = 0;
+ inode->i_nlink = 1;
+ inode->i_size = 0;
+ inode->i_blksize = 0;
+ inode->i_blocks = 0;
+ inode->i_mtime =
+ inode->i_atime =
+ inode->i_ctime = 0;
+ inode->i_op = NULL;
+}