patch-1.3.94 linux/fs/affs/inode.c
Next file: linux/fs/affs/namei.c
Previous file: linux/fs/affs/file.c
Back to the patch index
Back to the overall index
- Lines: 432
- Date:
Wed Mar 20 20:01:47 1996
- Orig file:
v1.3.93/linux/fs/affs/inode.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.93/linux/fs/affs/inode.c linux/fs/affs/inode.c
@@ -0,0 +1,431 @@
+/*
+ * linux/fs/affs/inode.c
+ *
+ * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem
+ *
+ * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ * (C) 1991 Linus Torvalds - minix filesystem
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+
+#include <linux/genhd.h>
+
+#include "amigaffs.h"
+
+extern int check_cdrom_media_change(int, int);
+
+#ifdef LEAK_CHECK
+static int check_malloc = 0;
+static int check_bread = 0;
+#endif
+
+void affs_put_super(struct super_block *sb)
+{
+ lock_super(sb);
+
+#ifdef LEAK_CHECK
+ printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
+ check_malloc, check_bread);
+#endif
+ sb->s_dev = 0;
+ unlock_super(sb);
+ return;
+}
+
+static struct super_operations affs_sops = {
+ affs_read_inode,
+ NULL, /* notify_change */
+ NULL, /* write_inode */
+ NULL, /* put_inode */
+ affs_put_super,
+ NULL, /* write_super */
+ affs_statfs,
+ NULL /* remount */
+};
+
+int affs_parent_ino(struct inode *dir)
+{
+ int root_ino = (dir->i_sb->u.affs_sb.s_root_block
+ - dir->i_sb->u.affs_sb.s_partition_offset);
+
+ if (!S_ISDIR (dir->i_mode)) {
+ printk ("affs_parent_ino: argument is not a directory\n");
+ return root_ino;
+ }
+ if (dir->i_ino == root_ino)
+ return root_ino;
+ return dir->u.affs_i.i_parent;
+}
+
+static int parse_options(char *options, struct affs_options *optp)
+{
+ char *this_opt,*value,*end;
+ int n;
+
+ optp->offset = 0;
+ optp->size = 0;
+ optp->root = 0;
+ optp->conv_links = 0;
+
+ if (!options)
+ return 1;
+ for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
+ if ((value = strchr(this_opt,'='))) *value++ = 0;
+
+ if (!strcmp(this_opt,"offset") && value) {
+ n = simple_strtoul (value, &end, 10);
+ if (end == value || *end != 0)
+ return 0;
+ optp->offset = n;
+ }
+ else if (!strcmp(this_opt,"size") && value) {
+ n = simple_strtoul (value, &end, 10);
+ if (end == value || *end != 0 || n <= 0)
+ return 0;
+ optp->size = n;
+ }
+ else if (!strcmp(this_opt,"root") && value) {
+ n = simple_strtoul (value, &end, 10);
+ if (end == value || *end != 0 || n <= 0)
+ return 0;
+ optp->root = n;
+ }
+ else if (!strcmp(this_opt,"conv_symlinks")) {
+ optp->conv_links = 1;
+ }
+ else return 0;
+ }
+ return 1;
+}
+
+/* Is this The Right Way? Should I be locking something? */
+
+static int get_device_size (dev_t dev)
+{
+ struct gendisk *gd_p;
+ int dev_size = 0;
+
+ for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
+ if (gd_p->major != MAJOR(dev))
+ continue;
+ dev_size = gd_p->part[MINOR(dev)].nr_sects;
+ break;
+ }
+ return dev_size;
+}
+
+struct super_block *affs_read_super(struct super_block *s,void *data,
+ int silent)
+{
+ struct buffer_head *bh;
+ int dev = s->s_dev;
+ int root_block;
+ int ptype, stype;
+ void *root_data;
+ struct affs_options *optp;
+
+ optp = &s->u.affs_sb.s_options;
+
+ if (!parse_options((char *) data, optp)) {
+ s->s_dev = 0;
+ printk ("AFFS: bad mount options\n");
+ return NULL;
+ }
+
+ lock_super(s);
+
+ root_block = 0;
+ if (optp->size) {
+ s->u.affs_sb.s_partition_size = optp->size;
+ }
+ else {
+ int size = get_device_size (dev);
+ if (size == 0) {
+ s->s_dev = 0;
+ unlock_super(s);
+ printk ("affs_read_super: could not"
+ "determine device size\n");
+ }
+ s->u.affs_sb.s_partition_size = size;
+ }
+
+ s->u.affs_sb.s_partition_offset = optp->offset;
+ root_block = optp->root;
+
+ if (!root_block)
+ root_block = (s->u.affs_sb.s_partition_offset
+ + s->u.affs_sb.s_partition_size / 2
+ + (s->u.affs_sb.s_partition_size & 1));
+ s->u.affs_sb.s_root_block = root_block;
+
+ s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
+
+#if 0
+ printk ("affs_read_super: dev=0x%04x offset=%d "
+ "size=%d root=%d blocksize=%d\n",
+ dev,
+ s->u.affs_sb.s_partition_offset,
+ s->u.affs_sb.s_partition_size,
+ s->u.affs_sb.s_root_block,
+ s->u.affs_sb.s_block_size);
+#endif
+
+ bh = affs_sread (dev, root_block, &root_data);
+ if (!bh) {
+ s->s_dev = 0;
+ unlock_super(s);
+ printk ("AFFS: unable to read superblock\n");
+ return NULL;
+ }
+
+ if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype)
+ || ptype != T_SHORT || stype != ST_ROOT) {
+ printk ("AFFS: invalid root block %d on device 0x%04x\n",
+ root_block, dev);
+ goto out;
+ }
+
+#if 1
+{
+ char *name;
+ int len;
+ char buf[33];
+ len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name);
+ memcpy (buf,name,len);
+ buf[len] = 0;
+#if 0
+ printk ("affs_read_super: volume name \"%s\"\n", buf);
+#endif
+}
+#endif
+
+ s->s_magic = AFFS_SUPER_MAGIC;
+
+ s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
+
+ brelse(bh);
+
+ /* set up enough so that it can read an inode */
+ s->s_dev = dev;
+ s->s_op = &affs_sops;
+ s->s_blocksize = AFFS_BUFFER_SIZE;
+ s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset);
+
+ unlock_super(s);
+
+ if (!(s->s_mounted)) {
+ s->s_dev = 0;
+ printk("AFFS: get root inode failed\n");
+ return NULL;
+ }
+
+ return s;
+
+ out: /* Kick out for various error conditions */
+ brelse (bh);
+ s->s_dev = 0;
+ unlock_super(s);
+ return NULL;
+}
+
+void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+#ifdef DEBUG
+ printk ("AFFS: affs_statfs called\n");
+#endif
+ put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
+ put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
+ put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
+ put_fs_long(0, &buf->f_bfree);
+ put_fs_long(0, &buf->f_bavail);
+ put_fs_long(0, &buf->f_files);
+ put_fs_long(0, &buf->f_ffree);
+ /* Don't know what value to put in buf->f_fsid */
+}
+
+static int prot_table[9][2] = {
+ {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE}, /* other: 1 = allowed */
+ {PROT_OTR_WRITE, PROT_OTR_WRITE},
+ {PROT_OTR_READ, PROT_OTR_READ},
+ {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE}, /* group: 1 = allowed */
+ {PROT_GRP_WRITE, PROT_GRP_WRITE},
+ {PROT_GRP_READ, PROT_GRP_READ},
+ {PROT_EXECUTE, 0}, /* owner: 0 = allowed */
+ {PROT_WRITE, 0},
+ {PROT_READ, 0}
+};
+
+void affs_read_inode(struct inode * inode)
+{
+ struct buffer_head *bh;
+ int block;
+ void *fh_data;
+ struct file_front *file_front;
+ struct file_end *file_end;
+ int i;
+ struct hardlink_end *link_end;
+ int link;
+
+#ifdef DEBUG
+ printk ("AFFS: entering affs_read_inode\n");
+#endif
+
+ inode->i_nlink = 1; /* at least */
+ do {
+ link = 0;
+ block = inode->i_ino;
+ if (!(bh=affs_pread (inode, block, &fh_data))) {
+ printk("AFFS: unable to read i-node block %d\n", block);
+ return;
+ }
+
+ file_front = (struct file_front *) fh_data;
+ file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as dir_end */
+ AFFS_I2BSIZE (inode));
+
+ /* don't use bitmap data for mode, uid & gid of the rootblock */
+ if (block == inode->i_sb->u.affs_sb.s_root_block) {
+ inode->u.affs_i.i_protect = 0;
+ inode->u.affs_i.i_parent = block;
+
+ inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ; /* drwxrwxrwt */
+ inode->i_nlink = 2; /* at least ..... */
+
+ inode->i_size = 0; /* some differrent idea ? */
+
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ }
+ else {
+
+ inode->u.affs_i.i_protect = file_end->protect;
+ inode->u.affs_i.i_parent = swap_long (file_end->parent);
+
+ inode->i_mode = 0;
+ for (i = 0; i < 9; i++)
+ if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
+ inode->i_mode |= 1<<i;
+ switch(swap_long(file_end->secondary_type)) {
+ case ST_USERDIR:
+ inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
+
+ inode->i_nlink++; /* There are always at least 2. It is
+ hard to figure out what is correct*/
+ inode->i_size = 0;
+ break;
+ case ST_SOFTLINK:
+ inode->i_mode |= S_IFLNK;
+ inode->i_size = 0;
+ break;
+ case ST_LINKFILE: /* doing things very easy (not really correct) */
+ case ST_LINKDIR: /* code is _very_ inefficient (see below) */
+
+ /* Where is struct link_end defined?
+ ... I don't know what is going on
+ here, someone else should
+ probably spend some time on this */
+ link_end = (struct hardlink_end *)file_end;
+ inode->i_ino = link_end->original;
+ inode->i_nlink += 2; /* It's hard to say whats correct */
+ brelse(bh);
+ link = 1;
+ break;
+ default:
+ printk("affs: unknown secondary type %ld; assuming file\n",
+ file_end->secondary_type);
+ case ST_FILE:
+ inode->i_mode |= S_IFREG;
+ inode->i_size = swap_long (file_end->byte_size);
+ break;
+ }
+ if (file_end->uid == 0xffff)
+ inode->i_uid = 0; /* root uid */
+ else if (file_end->uid == 0x0000) {
+ umode_t mode;
+ inode->i_uid = -1; /* unknown uid */
+
+ /*
+ * change the mode of the inode to duplicate the
+ * perms of the user in the group and other fields;
+ * the assumption is that this isn't a MultiUser
+ * filesystem/file, so the permissions should be
+ * the same for all users
+ */
+ mode = (inode->i_mode >> 6) & 7;
+ inode->i_mode |= (mode << 3) | (mode);
+ } else
+ inode->i_uid = file_end->uid;
+ if (file_end->gid == 0xffff)
+ inode->i_gid = 0; /* root gid */
+ else if (file_end->gid == 0x0000)
+ inode->i_gid = -1; /* unknown gid */
+ else
+ inode->i_gid = file_end->gid;
+ }
+ }
+ while (link);
+
+#ifdef DEBUG
+ printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
+#endif
+ inode->i_mtime = inode->i_atime = inode->i_ctime
+ = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
+ + swap_long (file_end->created.ds_Minute) * 60
+ + swap_long (file_end->created.ds_Tick) / 50
+ + ((8 * 365 + 2) * 24 * 60 * 60));
+
+ brelse(bh);
+
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &affs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &affs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &affs_symlink_inode_operations;
+}
+
+
+#ifdef LEAK_CHECK
+#undef malloc
+#undef free_s
+#undef bread
+#undef brelse
+
+void * leak_check_malloc(unsigned int size){
+ void * tmp;
+ check_malloc++;
+ tmp = kmalloc(size, GFP_ATOMIC);
+ return tmp;
+}
+
+void leak_check_free_s(void * obj, int size){
+ check_malloc--;
+ return kfree_s(obj, size);
+}
+
+struct buffer_head * leak_check_bread(int dev, int block, int size){
+ check_bread++;
+ return bread(dev, block, size);
+}
+
+void leak_check_brelse(struct buffer_head * bh){
+ check_bread--;
+ return brelse(bh);
+}
+
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this